Модераторы: 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   Вверх
Felan
Дата 23.8.2008, 11:48 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Опытный
**


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

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



Цитата(Rohoss @  22.8.2008,  20:10 Найти цитируемый пост)
Felan, вопрос в том, чтобы не переопределять класс TCommands

Ну тогда конечно такой способ не подойдет. Ибо я сразу сказал, "если есть возможность переделать архитектуру".

Цитата(Rohoss @  22.8.2008,  20:10 Найти цитируемый пост)
А если уже без переопределения класса никак, то чем твой метод лучше от использования динамического массива?

Тем, что это классика ООП. Следовательно проверена не раз на практике. Тем что он понятный, прозрачный, типо-безопасный, расширяемый. Ессно программист использующий его должен иметь определенный уровень, что бы четко понимать ООП, виртуальные конструкторы делфи. (не принимай на свой счет, просто это факт. Что бы с чем-то разобраться и понять нужны определенные знания и опыт).


Цитата(Rohoss @  22.8.2008,  20:10 Найти цитируемый пост)
1.    Не нужно процедуру парсинга писать для каждой команды.

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

Цитата(Rohoss @  22.8.2008,  20:10 Найти цитируемый пост)
2.    Получится более компактно.

Цель разработчика сделать код понятным, простым, устойчивым, что бы можно было его легко поддерживать исправлять. А компактность это не показатель. Можно все в одну строку написать без пробелов, будет еще компактнее. Как будешь читать модуль в 1000 символов?

С такой компактностью потеряешь все преимущества, про которые я говорил в предидущем пункте + к ним добавишь проблемы с ручным контролем типов.

Цитата(Rohoss @  22.8.2008,  20:10 Найти цитируемый пост)
3.    Можно использовать общие поля класса для всех команд

Вот это просто ОШИБКА проектирования! Пройдет пару месяцев и для того, что бы исправить одну команду будешь неделю проверять не затронуло ли это другую.
Зачем смешивать данные? Ты что для контроллера пишешь? Тебе принципиально сэкономить несколько байт?


Это конечно все не критично, если пишешь проект с тремя командами, который один раз отдашь кому-то и забудешь, а если у тебя будет много команд, тебе придется его поддерживать и расширять, исправлять ошибки, все это хлебнешь по полной smile

Ну а если тебе принципиально нельзя менять архитектуру, то выбирай из того, что тебе уже сказали. Или можешь все-таки сделать метод, который выбирает команду например таким:

Код

procedure (arg: TArgument) ofbject;


Где TArgument базой класс типа TCommand в моем варианте, а от него наследника для каждой команды. Тогда по типу класса сможешь определить точно, какую команду нужно вызвать а в полях объекта передать нужные данные.


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


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


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

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



Цитата(Felan @  23.8.2008,  11:48 Найти цитируемый пост)
Цитата(Rohoss @  22.8.2008,  20:10 )1.    Не нужно процедуру парсинга писать для каждой команды.Плохо. Т.к. будет одна процедура для всех команд. Команд много - процедура становится огромной, трудной для восприятия и понимания за счет объема. Для расширения списка команд обязательно требуется перекомпиляция и очень внимательное и осторожное добавление команды. Пройдет время и ты не сможешь изменить ее так, что бы не потратить кучу времени на отладку.В моем случае у каждой команды своя маленькая процедурка, ошибки в которой влияют только на эту команду. Проще поддерживать, отлаживать, ошибки локализуются.


Ну вот функция:
Код

TArrayParam = array of string;

function cParse(sCommandsParam:string):TArrayParam;
var
I:Integer;
ArraySize:Word;
sTemp:string;
n:Integer;
begin
ArraySize:=1;
SetLength(Result,ArraySize);
if Length(sCommandsParam)=0 then
begin
  Result[0]:='';
  Exit;
end;
n:=Pos('&',sCommandsParam);
if n=0 then n:=Length(sCommandsParam)else n:=n-1;
Result[0]:=Copy(sCommandsParam,0,n);
ShowMessage(Result[0]);
 for I := 0 to Length(sCommandsParam) do
  begin
   if sCommandsParam[I]='&' then
    begin
      sTemp:=Copy(sCommandsParam,I+1,Length(sCommandsParam)-I);
      n:=Pos('&',sTemp);
      if n=0 then n:=Length(sTemp) else n:=n-1;
      sTemp:=Copy(sTemp,0,n);
      Inc(ArraySize);
      SetLength(Result,ArraySize);
      Result[I]:=sTemp;
    end;
  end;
end;


Раз написал и забыл о парсинге… smile

Добавлено @ 14:44
А так выглядят функции класса TCommands
Код

function cCopyFile(ArsParam:TArrayParam):Boolean;
function cMoveRenameFile(ArsParam:TArrayParam):Boolean;


Это сообщение отредактировал(а) Rohoss - 23.8.2008, 14:48


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


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


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

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



Цитата(Felan @  23.8.2008,  11:48 Найти цитируемый пост)
Цитата(Rohoss @  22.8.2008,  20:10 )3.    Можно использовать общие поля класса для всех командВот это просто ОШИБКА проектирования! Пройдет пару месяцев и для того, что бы исправить одну команду будешь неделю проверять не затронуло ли это другую.Зачем смешивать данные? Ты что для контроллера пишешь? Тебе принципиально сэкономить несколько байт?

А почему они должны смешиваться? К примеру полем является класс для ведения логов
Код

fLog:TLogger;

у него функции типа
Код

function AddText(s:string):Boolean;

Почему они будут смешиваться? В принципе они независимы, разница в том, что этот класс создаётся один раз, а не для каждой команды. Каждый байт конечно не важен, но ИМХО это не оправдано… smile 



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


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


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

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



Цитата(Felan @  23.8.2008,  11:48 Найти цитируемый пост)
Ну а если тебе принципиально нельзя менять архитектуру, то выбирай из того, что тебе уже сказали. Или можешь все-таки сделать метод, который выбирает команду например таким:код Pascal/Delphi1:procedure (arg: TArgument) ofbject;highlightSyntax('delphi_YWQ0Mz','delphi');Где TArgument базой класс типа TCommand в моем варианте, а от него наследника для каждой команды. Тогда по типу класса сможешь определить точно, какую команду нужно вызвать а в полях объекта передать нужные данные.


ну, здесь я так понимаю опять же нужно переопределять класс… smile 
Дело в том, что TCommands писал не я, и в нём 186 команд, общей длиной 11700 строк  smile 




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


Опытный
**


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

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



Цитата(Rohoss @  23.8.2008,  16:36 Найти цитируемый пост)
Раз написал и забыл о парсинге…

Ну если так то хорошо. А если придется добавлять еще одну команду, которую надо будет парсить по другому?

Цитата(Rohoss @  23.8.2008,  17:00 Найти цитируемый пост)
Почему они будут смешиваться? В принципе они независимы, разница в том, что этот класс создаётся один раз, а не для каждой команды. Каждый байт конечно не важен, но ИМХО это не оправдано… smile 

Ну возможно я не совсем понял, что ты имеешь ввиду под "общими полями для всех команд".
Создашь один раз и он будет у тебя висеть все время, пока работает программа... В моем случае команда существует пока выполняется.

Цитата(Rohoss @  23.8.2008,  17:18 Найти цитируемый пост)
ну, здесь я так понимаю опять же нужно переопределять класс… smile 


Нет. Здесь как раз его не надо переопределять. Здесь ты делаешь обвязку для этого класса, которая изолирует его.

Цитата(Rohoss @  23.8.2008,  17:18 Найти цитируемый пост)
Дело в том, что TCommands писал не я, и в нём 186 команд, общей длиной 11700 строк  smile 

Не важно кто писал. Важно то, можешь ты его изменить или нет.
Вот видишь, количество команд уже большое. 

ЗЫЖ Количество классов одно, количество объектов - другое. Я не настаиваю на своем способе и не говорю, что твой не правильный. Я просто привел другой вариант, который на мой взгляд более правильный. Но это только на мой взгляд smile



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


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


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

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



Цитата(Felan @  23.8.2008,  16:45 Найти цитируемый пост)
Цитата(Rohoss @  23.8.2008,  17:18 )ну, здесь я так понимаю опять же нужно переопределять класс… smile Нет. Здесь как раз его не надо переопределять. Здесь ты делаешь обвязку для этого класса, которая изолирует его.

а можешь привести маленький пример?



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


Опытный
**


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

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



Ну я даже не знаю, Как тут его привести...

Ну например так:
Код

unit Unit4;

interface

uses
  Classes;

type
  //Твой класс, как есть
 TCommands = class
   function cCopyFile(OldFile, NewFile : string) : Boolean;
   function cDeleteFile(cFile : string) : Boolean;
 end;

 //Базовый класс, для унифицированного обращения
 TArguments = class
 public
  //метод который парсит строку с командой, если здесь ошибка,
  //то значит строка не соответствует предпологаемой команде
  //Сюда можно вынести код для парсинга однотипных команд, который пбудет просто
  //наследоваться, если таких команд много
  procedure TryParseString(aCMDString: String); virtual; abstract;
  //Выполняем команду. Каждый подкласс этого класса жестко обращается к нужной
  //команде
  procedure Execute(aOldCommands: TCommands); virtual; abstract;
 end;

 //конкретный подкласс для конкретной команды.
 //Парсинг и выполнение инкапсулированы в нем.
 TArguments_CopyFile = class(TArguments)
 private
  fOldFile: String;
  fNewFile: String;
 public
  procedure TryParseString(aCMDString: String); override;
  procedure Execute(aOldCommands: TCommands); override;
 end;

 //Объект-парсер, который обрабатывает файл
 TParser = class
   private
    fCMD: array of TArguments;
    function getObj(Ind: Integer): TArguments;
   public
    //Парсим команды и заполняем массив команд, к каждую команду в котором можно
    //выполнить универсально.
    procedure Parse(aStrs: TStringList);
    property CMDs[Ind: Integer]: TArguments read getObj; default;
 end;

implementation

{ TCommands }

function TCommands.cCopyFile(OldFile, NewFile: string): Boolean;
begin
  //Copy File
end;

function TCommands.cDeleteFile(cFile: string): Boolean;
begin
  //Delete File
end;

{ TParser }

function TParser.getObj(Ind: Integer): TArguments;
begin
  Result := fCMD[Ind];
end;

procedure TParser.Parse(aStrs: TStringList);
begin
  //Парсим команды и заполняем массив команд;
end;

{ TArguments_CopyFile }

procedure TArguments_CopyFile.Execute(aOldCommands: TCommands);
begin
  aOldCommands.cCopyFile(fOldFile, fNewFile);
end;

procedure TArguments_CopyFile.TryParseString(aCMDString: String);
begin
  //Парсим строку и заполняем параметры
end;

end.



ЗЫЖ Но учти, что это обертка smile Так что естественно некоторая "слоеность" логики smile


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


Эксперт
***


Профиль
Группа: Завсегдатай
Сообщений: 1839
Регистрация: 24.6.2008
Где: Россия, Тверь

Репутация: 38
Всего: 89



Пробежал тему по-диагонали.
Вопрос: есть имя метода, скажем, 'XXX'. Есть ли возможность узнать, сколько у него параметров в классе? Т.е. по имени определить число параметров? 
Если да, то я не вижу проблемы. Можно сделать, например, как-то так:

Код
type
Tnte1=procedure(s1:string) of object;
Tnte2=procedure(s1,s2:string) of object;
Tnte3=procedure(s1,s2,s3:string) of object;
Tnte4=procedure(s1,s2,s3,s4:string) of object;
...
Tnte20=procedure(s1,s2,s3,s4,s5,s6,s7,s8,s9,s10,s11,s12,s13,s14,s15,s16,s17,s18,s19,s20:string) of object;
begin
  ...
  case NomberOfArguments(Method) of
    1: Tnte1(Method)(S[0]);
    2: Tnte1(Method)(S[0], S[1]);
    3: Tnte1(Method)(S[0], S[1], S[2]);
    4: Tnte1(Method)(S[0], S[1], S[2], S[3]);
  ...
    20: Tnte1(Method)(S[0], S[1], S[2], S[3], S[4], S[5], ...);
  else
    raise ...;
  end;
end;


Не нравится объявление 20-ти типов? Можно вызвать процедуру и без них, если код вызова записать на ассемблере. Первые три аргумента пойдут по регистрам, остальные - циклом до числа параметров пихаются в стек, после чего делаем call.

P.S. Что будет, если число параметров у метода и число строк, которое мы напарсили, отличается?


--------------------
Опытный программист на C++ легко решает любые не существующие в Паскале проблемы.
PM MAIL WWW ICQ Skype GTalk Jabber   Вверх
Rohoss
Дата 25.8.2008, 21:20 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


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


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

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



Цитата(CodeMonkey @  25.8.2008,  11:19 Найти цитируемый пост)
Вопрос: есть имя метода, скажем, 'XXX'. Есть ли возможность узнать, сколько у него параметров в классе? 

Ты имел ввиду в функции? Хз, думаю как-то можно…

Цитата(CodeMonkey @  25.8.2008,  11:19 Найти цитируемый пост)
Не нравится объявление 20-ти типов? Можно вызвать процедуру и без них, если код вызова записать на ассемблере.

В ассемблере я полный ноль… smile 

Цитата(CodeMonkey @  25.8.2008,  11:19 Найти цитируемый пост)
P.S. Что будет, если число параметров у метода и число строк, которое мы напарсили, отличается?

Не понял вопроса… Если мы передадим в метод не то количество параметров которые у него есть smile ? Исключения наверное будет, или я не понял…

Добавлено через 7 минут и 13 секунд
Felan  твоего примера я пока не понял, попробую разобраться чуть позже, что-то он мне кажется сильно раздутым… Ты предлагаешь писать наследника TArguments для каждой команды??? smile  Если так, то мне в 50 раз проще будет изменить параметры функций класса TCommands


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


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


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

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



Цитата(Rohoss @  21.8.2008,  22:39 Найти цитируемый пост)
ama_kid либо я не понял твоего примера, либо ты не понял что я хочу
Может быть, конечно и второе, но посмотри, правильно ли я тебя понял на этот раз?
Код
unit Unit1;

interface

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

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

 TCommands = class
  published
   function cMethod1(Param:array of string):Boolean;
   function cMethod2(Param:array of string):Boolean;
   function cMethod3(Param:array of string):Boolean;
 end;

 type
  TNte = function(s:array of string):boolean of object;
var
  Form1: TForm1;
  TC:TCommands;
implementation

{$R *.dfm}

function ExecuteMetod(sName:string;Params:array of string):boolean;
var
 Method:TMethod;
 nte:TNte;
begin
 Result:=false;
 Method.Data:=TC;
 Method.Code:=TC.MethodAddress(sName);
 if Method.Code = nil then Exit;
 nte:=TNte(Method);
 Result:=nte(Params);
end;

procedure TForm1.Button1Click(Sender: TObject);
begin
 if ExecuteMetod('cMethod2',['String','String']) then
   ShowMessage('Execution of cMethod2 is Successfull');

 if ExecuteMetod('cMethod1',['Param']) then
   ShowMessage('Execution of cMethod1 is Successfull');

 if ExecuteMetod('cMethod3',['String','String','Param']) then
   ShowMessage('Execution of cMethod3 is Successfull');
end;

{ TCommands }

function TCommands.cMethod1(Param:array of string): Boolean;
begin
 Result:= Param[0] = 'Param';
end;

function TCommands.cMethod2(Param:array of string): Boolean;
begin
 Result:=CompareStr(Param[0],Param[1])=0;
end;

function TCommands.cMethod3(Param:array of string): Boolean;
begin
 Result:=(Param[0]=Param[1])and(Length(Param[2])<Length(Param[0]));
end;

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

procedure TForm1.FormDestroy(Sender: TObject);
begin
 TC.Free;
end;

end.



Добавлено
Цитата(Rohoss @  22.8.2008,  19:10 Найти цитируемый пост)
вопрос в том, чтобы не переопределять класс TCommands
а, ну после этого - я тебя понял smile Тогда да - сложно smile

Это сообщение отредактировал(а) ama_kid - 25.8.2008, 22:27


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


Эксперт
***


Профиль
Группа: Завсегдатай
Сообщений: 1839
Регистрация: 24.6.2008
Где: Россия, Тверь

Репутация: 38
Всего: 89



Цитата(Rohoss @  25.8.2008,  21:20 Найти цитируемый пост)
Ты имел ввиду в функции? Хз, думаю как-то можно…

Значит ваше кунг-фу ещё недостаточно хорошо ;)

Код
uses
  ObjAuto;

type
  {$M+}
  {$METHODINFO ON}
  TTestObj = class
  published
    procedure P1(S1: String);
    procedure P2(S1, S2: String);
    procedure P3(S1, S2, S3: String);
  end;

{ TTestObj }

procedure TTestObj.P1(S1: String);
begin
  OutputDebugString(PChar('"' + S1 + '"'));
end;

procedure TTestObj.P2(S1, S2: String);
begin
  OutputDebugString(PChar('"' + S1 + '", "' + S2 + '"'));
end;

procedure TTestObj.P3(S1, S2, S3: String);
begin
  OutputDebugString(PChar('"' + S1 + '", "' + S2 + '", "' + S3 + '"'));
end;

procedure TForm9.Button1Click(Sender: TObject);
type
  TParams = array of Variant;

  procedure CallMethod(const AObj: TObject; const AMethodName: String; const AParams: TParams);
  resourcestring
    sMethodNotFound = 'Method %s of class %s not found';
  var
    MI: PMethodInfoHeader;
    Ind: array of Integer;
    X: Integer;
  begin
    MI := GetMethodInfo(AObj, AMethodName);
    if not Assigned(MI) then
      raise Exception.CreateFmt(sMethodNotFound, [AMethodName, AObj.ClassName]);
    SetLength(Ind, Length(AParams));
    for X := 0 to High(Ind) do
      Ind[X] := X + 1;
    ObjectInvoke(AObj, MI, Ind, AParams);
  end;

var
  T: TTestObj;
  Arr: TParams;
begin
  T := TTestObj.Create;
  try

    SetLength(Arr, 1);
    Arr[0] := 'Test1';
    CallMethod(T, 'P1', Arr);

    SetLength(Arr, 2);
    Arr[1] := 'Test2';
    CallMethod(T, 'P2', Arr);

    SetLength(Arr, 3);
    Arr[2] := 'Test3';
    CallMethod(T, 'P3', Arr);

  finally
    FreeAndNil(T);
  end;
end;



--------------------
Опытный программист на C++ легко решает любые не существующие в Паскале проблемы.
PM MAIL WWW ICQ Skype GTalk Jabber   Вверх
Rohoss
Дата 26.8.2008, 20:27 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


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


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

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



CodeMonkey было бы очень не плохо если бы ты прокомментировал то, что написал… Так как гугл не заваливает инфой по запросу «delphi ObjAuto»  smile

Добавлено через 47 секунд
да и drbk тоже…


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


Эксперт
***


Профиль
Группа: Завсегдатай
Сообщений: 1839
Регистрация: 24.6.2008
Где: Россия, Тверь

Репутация: 38
Всего: 89



Всё это подробно разжёвывается, например, здесь: http://hallvards.blogspot.com/2006/09/exte...class-rtti.html и далее по ссылкам.

На русском: http://www.transl-gunsmoker.ru/2011/07/dig...nd-websnap.html (начало серии тут: http://www.transl-gunsmoker.ru/2011/07/pol...ad-nauseum.html )

P.S. Респект за попытку разобраться вместо бездумного копирования! smile 

Это сообщение отредактировал(а) CodeMonkey - 17.8.2011, 07:10


--------------------
Опытный программист на C++ легко решает любые не существующие в Паскале проблемы.
PM MAIL WWW ICQ Skype GTalk Jabber   Вверх
Rohoss
Дата 29.8.2008, 04:31 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


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


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

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



Цитата(CodeMonkey @  27.8.2008,  00:21 Найти цитируемый пост)
Всё это подробно разжёвывается, например, здесь: http://hallvards.blogspot.com/2006/09/exte...class-rtti.html и далее по ссылкам.P.S. Респект за попытку разобраться вместо бездумного копирования!  


Вроде в общих чертах понял! 
Спасибо!




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


Эксперт
***


Профиль
Группа: Завсегдатай
Сообщений: 1839
Регистрация: 24.6.2008
Где: Россия, Тверь

Репутация: 38
Всего: 89



Начиная с Delphi 2010 появилась новая RTTI, где можно делать много новых вещей.

Немного ссылок:
http://robstechcorner.blogspot.com/2009/09...tti-basics.html
http://habrahabr.ru/blogs/delphi/86840/
http://delphi.about.com/od/oopindelphi/a/delphirtti.htm
http://robstechcorner.blogspot.com/search/label/RTTI

Код
program Project11;
{$APPTYPE CONSOLE}
uses
  StdCtrls, TypInfo, Classes, Rtti;
var
  c: TRttiContext; 
  m: TRttiMethod; 
  t : TRttiInstanceType;
  SL: TValue; 
  Lines: TValue;
begin
  c := TRttiContext.Create;
  try
    t := c.FindType('Classes.TStringList') as TRttiInstanceType;
    SL := t.GetMethod('Create').Invoke(t.MetaclassType, []);

    t.GetMethod('Add').Invoke(SL, ['Hello Do you like my hat?']);
    t.GetMethod('Add').Invoke(SL, ['I like that hat, what a party hat!']);

    Lines := t.GetProperty('Text').GetValue(SL.AsObject);

    Writeln(Lines.ToString);
  finally
    FreeAndNil(c);
  end;
  ReadLn;
end.


Это сообщение отредактировал(а) CodeMonkey - 13.9.2010, 20:51


--------------------
Опытный программист на C++ легко решает любые не существующие в Паскале проблемы.
PM MAIL WWW ICQ Skype GTalk Jabber   Вверх
bems
Дата 13.9.2010, 22:42 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
****


Профиль
Группа: Комодератор
Сообщений: 3400
Регистрация: 5.1.2006

Репутация: 31
Всего: 88




M
bems
Оффтоп удалён. Или вернитесь к теме обсуждения, или перестаньте насиловать труп



--------------------
Обижено школьников: 8
PM MAIL   Вверх
Страницы: (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.2055 ]   [ Использовано запросов: 21 ]   [ GZIP включён ]


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

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