Модераторы: Poseidon, Snowy, bems, MetalFan

Поиск:

Ответ в темуСоздание новой темы Создание опроса
> Динамическая генерация процедур, Или не знаю как назвать… 
V
    Опции темы
Rohoss
Дата 19.8.2008, 20:09 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Начальник интернета
***


Профиль
Группа: Завсегдатай
Сообщений: 1308
Регистрация: 9.10.2006
Где: Matrix

Репутация: 4
Всего: 18



Есть класс с множеством методов
Код

{$M+}
 TCommands = class
   function cCopyFile(OldFile,NewFile:string):Boolean;
   function cMoveRenameFile(OldFile,NewFile:string):Boolean;
   function cDeleteFile(cFile:string):Boolean;
   ..........

Мне нужно вызывать разные методы этого класса, типа как здесь
Код

type
Tnte=procedure(s:string) of object;
var
Method:TMethod;
nte:Tnte;
begin
Method.Data:=tc;
Method.Code:=tc.MethodAddress(' cCopyFile');
if Method.Code = nil then Exit;
nte:=Tnte(Method);
nte('test');
end;


только здесь у процедуры один параметр, а мне нужно чтобы количество параметров менялось. Для того чтобы этим процедурным типом можно было вызвать любой метод класса TCommands

Надеюсь у меня получилось правильно выразить мысль  smile 

Это сообщение отредактировал(а) Rohoss - 19.8.2008, 20:38


--------------------
Файловый менеджер Explorer.Net скачать  video
PM ICQ   Вверх
Rohoss
Дата 20.8.2008, 02:19 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Начальник интернета
***


Профиль
Группа: Завсегдатай
Сообщений: 1308
Регистрация: 9.10.2006
Где: Matrix

Репутация: 4
Всего: 18



Возможно ли такое вообще?


--------------------
Файловый менеджер Explorer.Net скачать  video
PM ICQ   Вверх
Rennigth
Дата 20.8.2008, 10:56 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
***


Профиль
Группа: Участник Клуба
Сообщений: 1708
Регистрация: 21.6.2004
Где: Moscow

Репутация: 49
Всего: 76



Цитата(Rohoss @  20.8.2008,  02:19 Найти цитируемый пост)
Возможно ли такое вообще? 

хм, ну в принципе как Tnte объявишь, так и вызывай... в чем проблемма то?


--------------------
(* Honesta mors turpi vita potior *)
PM MAIL ICQ   Вверх
Rohoss
Дата 20.8.2008, 21:08 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Начальник интернета
***


Профиль
Группа: Завсегдатай
Сообщений: 1308
Регистрация: 9.10.2006
Где: Matrix

Репутация: 4
Всего: 18



Так функции имеют разное количество параметров, причём не известно, сколько их будет (параметров).

Добавлено через 1 минуту и 45 секунд
Нужно как-то Tnte объявить как функцию с динамическим количеством параметров.

Добавлено через 7 минут и 14 секунд
Можно было параметром использовать динамический массив, но класс TCommands уже определён


--------------------
Файловый менеджер Explorer.Net скачать  video
PM ICQ   Вверх
Zmiy
Дата 20.8.2008, 22:05 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Новичок



Профиль
Группа: Участник
Сообщений: 39
Регистрация: 3.3.2007

Репутация: нет
Всего: 2



Rohoss, все параметры - строки?

Добавлено через 10 минут и 58 секунд
Не знаю, попробуй
Код

tnde = procedure (const a: array of String) of object;

или
Код

tnde = procedure (const a: array of const) of object;


PM MAIL   Вверх
ama_kid
Дата 20.8.2008, 22:28 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


АСУТП-кодер
***


Профиль
Группа: Комодератор
Сообщений: 1460
Регистрация: 5.3.2007
Где: Москва

Репутация: 15
Всего: 95



Цитата(Rohoss @  20.8.2008,  22:08 Найти цитируемый пост)
Нужно как-то Tnte объявить как функцию с динамическим количеством параметров.
Сделать-то это не мудрено:
Код
procedure Tnte(Caption:string; Args:array of const);
var
 s:string;
 i:integer;
begin
 s:='Parameters: ';
 for i:=0 to High(Args) do
  case Args[i].VType of
   vtInteger: s:=s+IntToStr(Args[i].VInteger)+', ';
   vtAnsiString:  s:=s+string(PChar(Args[i].VString))+', ';
   vtBoolean: s:=s+BoolToStr(Args[i].VBoolean)+', ';
   vtExtended: s:=s+FloatToStr(PExtended(Args[i].VExtended)^);
  end;
 MessageBox(0,PAnsiChar(s),PAnsiChar(Caption),0);
end;

procedure TForm1.Button1Click(Sender: TObject);
begin
 DecimalSeparator:='.';
 Tnte('Caption',[1,true,'word']);
 Tnte('Caption',[false,'byte',-5438,4.65]);
end;
Только имхо ты пытаешься решать задачу с неопределенностью. Мне кажется проще убрать неопределенность...


--------------------
самурай без меча подобен самураю с мечом, но только без меча 
PM MAIL   Вверх
Rohoss
Дата 20.8.2008, 22:52 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Начальник интернета
***


Профиль
Группа: Завсегдатай
Сообщений: 1308
Регистрация: 9.10.2006
Где: Matrix

Репутация: 4
Всего: 18



Цитата(Zmiy @  20.8.2008,  22:05 Найти цитируемый пост)
Rohoss, все параметры - строки?

Да

Код

unit Unit1;

interface

uses
  Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
  Dialogs, StdCtrls;

type
  TForm1 = class(TForm)
    btn1: TButton;
    procedure btn1Click(Sender: TObject);
    procedure FormCreate(Sender: TObject);
  private
    { Private declarations }
  public
    { Public declarations }
  end;

{$M+}
 TCommands = class
   function cCopyFile(OldFile,NewFile:string):Boolean;
   function cDeleteFile(cFile:string):Boolean;
 end;


var
  Form1: TForm1;
  tc:TCommands;

implementation

{$R *.dfm}

procedure TForm1.btn1Click(Sender: TObject);
type
ars=array of string;
tnte = function(const a: ars):Boolean of object;
var
Method:TMethod;
nte:Tnte;
c:ars;
begin
SetLength(c,2);
c[0]:='test';
c[1]:='dff';
Method.Data:=tc;
Method.Code:=tc.MethodAddress('cCopyFile');
if Method.Code = nil then Exit;
nte:=Tnte(Method);
nte(c);
end;

procedure TForm1.FormCreate(Sender: TObject);
begin
tc:=TCommands.Create;
end;

function TCommands.cCopyFile(OldFile: string; NewFile: string):Boolean;
begin
 ShowMessage(OldFile+'!copy!'+NewFile);
 Result:=True;
end;

function TCommands.cDeleteFile(cFile: string):Boolean;
begin
 ShowMessage('!Delete!'+cFile);
 Result:=True;
end;

end.


Сделал типо теста, сообщения выходят бредовые… 



--------------------
Файловый менеджер Explorer.Net скачать  video
PM ICQ   Вверх
Rohoss
Дата 20.8.2008, 23:16 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Начальник интернета
***


Профиль
Группа: Завсегдатай
Сообщений: 1308
Регистрация: 9.10.2006
Где: Matrix

Репутация: 4
Всего: 18



ama_kid немного не то… Тип должен использоватся для функции с разным количеством параметрами, а у тебя параметр массив… 

Это сообщение отредактировал(а) Rohoss - 20.8.2008, 23:18


--------------------
Файловый менеджер Explorer.Net скачать  video
PM ICQ   Вверх
ama_kid
Дата 21.8.2008, 07:08 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


АСУТП-кодер
***


Профиль
Группа: Комодератор
Сообщений: 1460
Регистрация: 5.3.2007
Где: Москва

Репутация: 15
Всего: 95



Цитата(Rohoss @  21.8.2008,  00:16 Найти цитируемый пост)
Тип должен использоватся для функции с разным количеством параметрами, а у тебя параметр массив… 
Этот массив параметрами может содержать переменные любых типов в любом количестве и любом порядке smile :
Код
procedure TForm1.Button1Click(Sender: TObject);
var
 s:string;
 r:real;
 a:integer;
 b:boolean;
begin
 DecimalSeparator:='.';
 s:='string';
 r:=3.24;
 a:=-5322;
 b:=true;
 Tnte('Caption',[r,s,a,b]);
 Tnte('Caption',[a,b,r]);
end;




--------------------
самурай без меча подобен самураю с мечом, но только без меча 
PM MAIL   Вверх
Felan
Дата 21.8.2008, 08:39 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Опытный
**


Профиль
Группа: Участник
Сообщений: 284
Регистрация: 2.8.2007
Где: Самара

Репутация: 2
Всего: 7



Тебе придется делать метод с переменным числом аргументов, потом проверять типы и приводить типы аргументов. Без этого не как. Есть другой вариант,
если есть возможность переделать архитектуру классов, то смотри в сторону паттерна проектирования Command. И, если неизвестно изначально, какие команды могут быть, смотри виртуальные конструкторы.

Общая суть такая:

Код

unit Unit3;

interface

type
  TCommand = class;

  //Мета-класс
  TCommandClass = class of TCommand;

  //Базовый класс команды
  TCommand = class
    private
      fLabel: String;
    public
      constructor Create(); virtual;
      procedure Execute(); virtual; abstract; //Метод выполняющий команду
      procedure Tune(); virtual; abstract; //Этот метод используется для того, что бы команды, еще не известные на этапе проектирования могли самонастраиваться!
  end;

  //Отдельная команда 1
  TCommand1 = class(TCommand)
    public
      Arg1: Integer;
      procedure Execute(); override;
      procedure Tune(); override;
  end;

  //Отдельная команда 2
  TCommand2 = class(TCommand)
    public
      Arg1: String;
      procedure Execute(); override;
      procedure Tune(); override;
  end;

  //Отдельная команда 3
  TCommand3 = class(TCommand)
    public
      Arg1: String;
      Arg2: Integer;
      procedure Execute(); override;
      procedure Tune(); override;
  end;

//Процедура демонстрирующая ипользование
procedure ExecuteCommands;

//Функция создающая неизвестную команду через вирт. конструктор, т.к. неизвестно, какие у нее могут быть параметры
function CreateUnknownCMD(cmdClass: TCommandClass): TCommand;

implementation

uses
  Dialogs, SysUtils;

procedure ExecuteCommands;
var
  vCmd: TCommand;
begin
  vCmd := TCommand1.Create();
  try
    With (vCmd as TCommand1) do
      begin
        Arg1 := 10;
      end;
    vCmd.Execute();
  finally
    FreeAndNil( vCmd );
  end;

  vCmd := TCommand2.Create();
  try
    With (vCmd as TCommand2) do
      begin
        Arg1 := 'Строка';
      end;
    vCmd.Execute();
  finally
    FreeAndNil( vCmd );
  end;

  vCmd := CreateUnknownCMD(TCommand3);
  try
    vCmd.Execute();
  finally
    FreeAndNil( vCmd );
  end;
end;

function CreateUnknownCMD(cmdClass: TCommandClass): TCommand;
var
  vCmd: TCommand;
begin
  vCmd := cmdClass.Create();
  vCmd.Tune(); //Настройка неизвестной команды, которая сама знает как настраиваться
  Result := vCmd;
end;

{ TCommand }

constructor TCommand.Create;
begin
  fLabel := ClassName;
end;

{ TCommand1 }

procedure TCommand1.Execute;
begin
  ShowMessage(Format('Аргумент команды %d', [Arg1]));
end;

procedure TCommand1.Tune;
begin
  Arg1 := 0; //Или исключение, если эта команда не должна вызвываться как неизвестная!
end;

{ TCommand2 }

procedure TCommand2.Execute;
begin
  ShowMessage(Format('Аргумент команды "%s"', [Arg1]));
end;

procedure TCommand2.Tune;
begin
  Arg1 := ''; //Или исключение, если эта команда не должна вызвываться как неизвестная!
end;

{ TCommand3 }

procedure TCommand3.Execute;
begin
  ShowMessage(Format('Аргументы команды "%s", %d', [Arg1, Arg2]));
end;

procedure TCommand3.Tune;
begin
  //Здесь можно вызывать отдельный диалог, который будет настраиывать команду.
  Arg1 := 'Автонастройка команды';
  Arg2 := 999;
end;

end.



Тест кода:

Код

procedure TForm2.Button1Click(Sender: TObject);
begin
  ExecuteCommands();
end;




Это сообщение отредактировал(а) Felan - 21.8.2008, 08:42


--------------------
// Любая сложная система - это темный лес. Каждый в этом лесу протаптывает свои тропинки, по ним и бегает. Лишь изредка, сходя с них, мы находим много интересного, а порою и страшного.
PM MAIL WWW ICQ   Вверх
Rohoss
Дата 21.8.2008, 21:39 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Начальник интернета
***


Профиль
Группа: Завсегдатай
Сообщений: 1308
Регистрация: 9.10.2006
Где: Matrix

Репутация: 4
Всего: 18



ama_kid либо я не понял твоего примера, либо ты не понял что я хочу…
Есть, к примеру, текстовый файл fun.txt
Код

start C:\1.txt
delete C:\temp.tmp
сopy C:\1.txt&D:\2.txt

приложения должно читать каждую строчку этого файла, вызывать метод класса TCommands и передавать этому методу параметрами то что идёт после пробела. «&» - разделитель между параметрами. Команды класса TCommands будут добавляться, а некоторые будут экспортироваться с dll, поэтому заранее определить не получится.

Добавлено через 10 минут и 56 секунд
Felan в твоём примере запутался, разберусь и отпишусь чуть позже… smile 

Это сообщение отредактировал(а) Rohoss - 21.8.2008, 21:40


--------------------
Файловый менеджер Explorer.Net скачать  video
PM ICQ   Вверх
THandle
Дата 21.8.2008, 21:54 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Хранитель Клуба
Group Icon
Награды: 1



Профиль
Группа: Админ
Сообщений: 3639
Регистрация: 31.7.2007
Где: Moscow, Dubai

Репутация: 65
Всего: 372



Rohoss, может и глупость сейчас говорю... Но что если сделать тип TNte с максимальным для методов класса TCommands параметров?

То есть например:

Код

unit Unit1;

interface

uses
  Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
  Dialogs, StdCtrls;

type
  TForm1 = class(TForm)
    Button1: TButton;
    Button2: TButton;
    procedure Button1Click(Sender: TObject);
    procedure FormCreate(Sender: TObject);
    procedure Button2Click(Sender: TObject);
  private
    { Private declarations }
  public
    { Public declarations }
  end;

{$M+}
 TCommands = class
   function cCopyFile(OldFile, NewFile : string) : Boolean;
   function cDeleteFile(cFile : string) : Boolean;
 end;

  TNte = function(Str, Str2 : string) : Boolean of object;

var
  Form1: TForm1;
  tc : TCommands;

implementation

{$R *.dfm}

procedure TForm1.Button1Click(Sender: TObject);
var
  Method : TMethod;
  Nte : TNte;
begin
  Method.Data := tc;
  Method.Code := tc.MethodAddress('cDeleteFile');
  if Method.Code = nil then Exit;
  Nte:=Tnte(Method);
  Nte('AAA', '');
end;

procedure TForm1.FormCreate(Sender: TObject);
begin
  tc:=TCommands.Create;
end;

function TCommands.cCopyFile(OldFile: string; NewFile: string):Boolean;
begin
  ShowMessage(OldFile+'!copy!'+NewFile);
  Result:=True;
end;
function TCommands.cDeleteFile(cFile: string):Boolean;
begin
  ShowMessage('!Delete!'+cFile);
  Result:=True;
end;

procedure TForm1.Button2Click(Sender: TObject);
var
  Method : TMethod;
  Nte : TNte;
begin
  Method.Data := tc;
  Method.Code := tc.MethodAddress('cCopyFile');
  if Method.Code = nil then Exit;
  Nte:=Tnte(Method);
  Nte('AAA', 'asss');
end;

end.

PM   Вверх
Rohoss
Дата 21.8.2008, 22:00 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Начальник интернета
***


Профиль
Группа: Завсегдатай
Сообщений: 1308
Регистрация: 9.10.2006
Где: Matrix

Репутация: 4
Всего: 18



Felan для каждой команды создавать свой класс? smile

Добавлено через 4 минуты и 38 секунд
THandle там точно есть команда с больше чем десятью параметрами… это не весь код класса TCommands. Пока единственный способ вижу изменять класс TCommands (сделать параметром динамический массив), но этого очень не хотелось.


--------------------
Файловый менеджер Explorer.Net скачать  video
PM ICQ   Вверх
Felan
Дата 22.8.2008, 07:25 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Опытный
**


Профиль
Группа: Участник
Сообщений: 284
Регистрация: 2.8.2007
Где: Самара

Репутация: 2
Всего: 7



Цитата(Rohoss @  21.8.2008,  23:39 Найти цитируемый пост)
Felan в твоём примере запутался, разберусь и отпишусь чуть позже…

Почитай про паттерны проектирования. Это паттерн "Команда" и все станет понятно. smile

Цитата(Rohoss @  22.8.2008,  00:00 Найти цитируемый пост)
Felan для каждой команды создавать свой класс? smile

Ну и что? В чем проблема-то? Зато каждая команда будет полностью самостоятельной единицей, которую ты сможешь править независимо ни от чего, и все изменения будут локализованы.
Лучше что-ли когда у тебя класс с мильоном методов, да еще не дай бог, перегруженных? Да с переменными аргументами? Да тип у этих аргументов общий, который нужно приводить на месте к нужному типу? Да за порядком этих аргументов нужно тщательно следить, за безопасностью типов тоже... за их правильным приведением... Чуть что, все надо перелопачивать... опухнуть можно smile

Цитата(Rohoss @  21.8.2008,  23:39 Найти цитируемый пост)
Есть, к примеру, текстовый файл fun.txt
Код

start C:\1.txt
delete C:\temp.tmp
сopy C:\1.txt&D:\2.txt

приложения должно читать каждую строчку этого файла, вызывать метод класса TCommands и передавать этому методу параметрами то что идёт после пробела. «&» - разделитель между параметрами. Команды класса TCommands будут добавляться, а некоторые будут экспортироваться с dll, поэтому заранее определить не получится.


И вот это как раз реализуется отлично. В моем примере добавляешь абстрактный метод Parse, в каждой команде реализуешь специфичный для нее парсинг строки. Динамически, создаешь нужную команду и выполняешь ее.... Все работает.
В принципе, я тебе даже показал способ как можно команды без перекомпиляции добавлять... Только нужно будет их хранить в длл, и использовать паккаджи для общих классов.

ЗЫЖ Логика такая. Есть базвый класс команды. Он используется для полиморфного выполнения и передачи объекта !ЛЮБОЙ! команды, которая унаследована от него (тут правда можно еще интерфейс использовать, но тогда не получит использовать виртуальные конструкторы напрямую). Каждая команда предаставляет собой класс-наследник базовой команды, которые реализует специфичный для себя функционал и инкапсулирует в себе все вспомогательные действия типа парсинга строки команды.... Все команды выполняются единообразно, после того как создается и настраивается класс команды. Их даже хранить не надо, создал команду, когда понадобилась, выполнил ее, уничтожил... 

Это сообщение отредактировал(а) Felan - 22.8.2008, 07:29


--------------------
// Любая сложная система - это темный лес. Каждый в этом лесу протаптывает свои тропинки, по ним и бегает. Лишь изредка, сходя с них, мы находим много интересного, а порою и страшного.
PM MAIL WWW ICQ   Вверх
Rohoss
Дата 22.8.2008, 18:10 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Начальник интернета
***


Профиль
Группа: Завсегдатай
Сообщений: 1308
Регистрация: 9.10.2006
Где: Matrix

Репутация: 4
Всего: 18



Felan, вопрос в том, чтобы не переопределять класс TCommands

Добавлено через 12 минут и 8 секунд
А если уже без переопределения класса никак, то чем твой метод лучше от использования динамического массива?
1.    Не нужно процедуру парсинга писать для каждой команды.
2.    Получится более компактно.
3.    Можно использовать общие поля класса для всех команд



--------------------
Файловый менеджер Explorer.Net скачать  video
PM ICQ   Вверх
Страницы: (3) Все [1] 2 3 
Ответ в темуСоздание новой темы Создание опроса
Правила форума "Delphi: Общие вопросы"
SnowyMetalFan
bemsPoseidon
Rrader

Запрещается!

1. Публиковать ссылки на вскрытые компоненты

2. Обсуждать взлом компонентов и делиться вскрытыми компонентами

  • Литературу по Дельфи обсуждаем здесь
  • Действия модераторов можно обсудить здесь
  • С просьбами о написании курсовой, реферата и т.п. обращаться сюда
  • Вопросы по реализации алгоритмов рассматриваются здесь
  • 90% ответов на свои вопросы можно найти в DRKB (Delphi Russian Knowledge Base) - крупнейшем в рунете сборнике материалов по Дельфи


Если Вам понравилась атмосфера форума, заходите к нам чаще! С уважением, Snowy, MetalFan, bems, Poseidon, Rrader.

 
1 Пользователей читают эту тему (1 Гостей и 0 Скрытых Пользователей)
0 Пользователей:
« Предыдущая тема | Delphi: Общие вопросы | Следующая тема »


 




[ Время генерации скрипта: 0.1392 ]   [ Использовано запросов: 21 ]   [ GZIP включён ]


Реклама на сайте     Информационное спонсорство

 
По вопросам размещения рекламы пишите на vladimir(sobaka)vingrad.ru
Отказ от ответственности     Powered by Invision Power Board(R) 1.3 © 2003  IPS, Inc.