![]() |
| ||
|
|
Новости |
Поиск |
FAQ |
Статьи |
Книги |
Новости VCL
| | Форумы ЧАТ |
Орешник |
|
| |||
| |||
« предыдущая ветвь | форум | следующая ветвь »
Как описать входной параметр процедуры многовариантно?
lipskiy © (2002-04-05 21:43:00)Ребята, я тут уже спрашивал, как можно описать входной параметр процедуры в мультивариантном виде, мне предложили использовать перегрузку. Но при перегрузке надо описывать два тела процедур, а если они объемные и почти одинаковые, отличаются только несколькими строчками, то описывать дважды одно и то же не хочется.
Может быть есть все-таки вариант описания входного параметра в виде списка возможных типов?
Конкретно мне нужно следующее:
proceudre Some(Input:String);
proceudre Some(Input:TStringList);
Параметр Input мне нужно описать так, чтобы при вызове ОДНОЙ процедуры Some можно было задать или String, или TStringList.
Как это сделать?
Вася Пупкин (2002-04-06 07:29:00) [21]2Fantasist (06.04.02 06:56)А Вы пробовали это запустить ?
Вся беда в том, что variant не может содержать ссілку на данные типа Pointer или class... боюсь, тут придется несколько больше "извращаться" :(
procedure sm(vt:TObject); overload;
var
v:variant;
begin
TVarData(v).VType:=varByRef;
TVarData(v).VPointer:=Pointer(vt);
sm(v); // здесь получите Error....
end;
Fantasist (2002-04-06 06:56:00) [22]Variant - вещь замечательная. Для простых типов. И перегрузка вещь замечательная. Я бы скомбинировал так:
procedure sm(vr:variant); overload;
begin
if TVarData(v).VType=varByRef then
TButton(Pointer(TVarData(vr).VPointer)).Caption:="t"
else
....
end;
procedure sm(vt:TObject); overload;
var
v:variant;
begin
TVarData(v).VType:=varByRef;
TVarData(v).VPointer:=Pointer(vt);
sm(v);
end;
procedure TForm1.Button1Click(Sender: TObject);
begin
sm(Sender);
end;
Можно еще в TVarData.Reserved1 добавить служебную информацию, что за класс. А если маленько подумать, то можно сделать переменную типа ClassId:class of TObject и распихать ее по TVarData.Reserved1 и TVarData.Reserved2 и тогда можно вообще красиво анализировать. Типа:
case classId of
TObject:
TButton:
.....
Вася Пупкин (2002-04-06 06:50:00) [23]либо так (это уж зависит от потребностей):
procedure TForm1.some(v:TStringList);
var i:integer;
begin
for i:=0 to V.Count-1 do some(v[i]);
end;
procedure TForm1.some(V:string);
begin
//Что-то делаем
end;
Вася Пупкин (2002-04-06 06:39:00) [24]А то, что два тела - так можно же сделать, например, так :
...при этом второе "тело" будет очень небольшим ;)
{ Private declarations }
procedure some(V:TStringList);reintroduce;overload;
procedure some(v:String);reintroduce;overload;
public
{ Public declarations }
end;
....
implementation
{$R *.DFM}
procedure TForm1.some(v:TStringList);
begin
// Form1.Label1.Caption:=v[0];
//Что-то делаем
end;
procedure TForm1.some(V:string);
//сделаем из string StringList
var Tmp:TStringList;
begin
Tmp:=TStringList.Create;
Tmp.Add(v);
//И вызовем перегруженную функцию для StringList
some(Tmp);
end;
Вася Пупкин (2002-04-06 05:44:00) [25]Да уж...на TStringList как-то не посмотрел...
Варианты не могут быть ссылками на объекты Object Pascal. Поэтому VID © (06.04.02 01:48) "Variant не подходит... комплятор ругается " абсолютно прав.
Так что для случая
proceudre Some(Input:String);
proceudre Some(Input:TStringList);
остается либо писать "извраты" - один из вариантов -SPeller © (06.04.02 02:12)... либо использовать reintroduce ( имхо, это проще...)
Пример использования reintroduce для конкретного случая (немного усложним)
proceudre Some(Input:variant);
proceudre Some(Input:TStringList);
unit Unit1;
interface
uses
Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms, Dialogs,
StdCtrls;
type
TForm1 = class(TForm)
Label1: TLabel;
Label2: TLabel;
Label3: TLabel;
Button1: TButton;
procedure Button1Click(Sender: TObject);
procedure FormCreate(Sender: TObject);
private
{ Private declarations }
procedure Some(V:variant);reintroduce;overload;
procedure Some(V:TStringList);reintroduce;overload;
public
{ Public declarations }
end;
var
Form1: TForm1;
L:TStringList;
implementation
{$R *.DFM}
procedure TForm1.Some(V:variant);
begin
Form1.Label3.Caption:=v
end;
procedure TForm1.Some(v:TStringList);
begin
Form1.Label1.Caption:=v[0];
Form1.Label2.Caption:=v[1];
end;
procedure TForm1.Button1Click(Sender: TObject);
begin
Some("123");
Some(L);
end;
procedure TForm1.FormCreate(Sender: TObject);
begin
L:=TStringList.Create;
L.Add("AAA");
L.Add("BBB");
end;
end.
SPeller (2002-04-06 03:48:00) [26]Можно сделать как я уже предлагал. Чтобы передать несколько строк, можно воспользоваться принципом как в ф-ции GetOpenFileName при передаче фильтров. Сделать свою ф-цию, которая выполняет всю эту рутину и передавать ей StringList, а она возвратит то, что надо. Мне кажется, это не так сложно, и выполняться оно будет быстрее, нежели обработка вариантов.
Вася Пупкин (2002-04-06 02:24:00) [27]SPeller © (06.04.02 02:12)Хороший вариант :)(сорьки, каламбур получился). Но не всегда годится.
SPeller (2002-04-06 02:12:00) [28]А если передавать в процедуру один параметр - указатель, а второй - идентификатор на что этот указатель указывает ?? И не надо никаких вариантов ?
Вася Пупкин (2002-04-06 02:07:00) [29]У меня не ругается :)
unit Unit1;
interface
uses
Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms, Dialogs, StdCtrls;
type
TForm1 = class(TForm)
Button1: TButton;
Label1: TLabel;
Button2: TButton;
procedure Button1Click(Sender: TObject);
procedure Button2Click(Sender: TObject);
private
{ Private declarations }
public
{ Public declarations }
end;
var
Form1: TForm1;
implementation
{$R *.DFM}
procedure Foo(V:variant);
begin
Form1.Label1.Caption:=v;
end;
procedure TForm1.Button1Click(Sender: TObject);
begin
Foo("String");
end;
procedure TForm1.Button2Click(Sender: TObject);
begin
Foo(123);
end;
end.
VID (2002-04-06 01:48:00) [30]TO Вася Пупкин: Variant не подходит... комплятор ругается :(
VID (2002-04-06 01:46:00) [31]можно пойти на изврат для конкретного случая:
Procedure Some (input:TStringList; IsTypeString:Boolean);
//В параметре input передаёшь список
//В параметре IsTypeString ставишь TRUE когда передаёшь строку, иначе - FALSE
begin
IF IsTypeString = true then
begin
Result := Input.Items.Strings[0]; //В этой строке списка и должно находиться нужное строковое значение
end
else
begin
Result := Input.Items.Count //В этом случае процедура работает уже как-бы со списком
end;
end;
спору нет - изврат, но сгодится :)))
Вася Пупкин (2002-04-06 01:46:00) [32]Или пользуй VARIANT VID © (06.04.02 01:00)
Вася Пупкин (2002-04-06 01:44:00) [33]Ну дык ... у тебя и получится уникальный список параметров:
type
TForm1 = class(TForm)
....
private
procedure Close(S:string);reintroduce;overload;
procedure Close(i:integer);reintroduce;overload;
procedure Close(i,j:integer);reintroduce;overload;
implementation
...
procedure TForm1.Close(S:string);
begin
....
end;
procedure TForm1.Close(i:integer);
begin
....
end;
lipskiy (2002-04-06 01:35:00) [34]Дык мне не надо так.
Мне надо один метод, но чтоб один из входных параметров мог быть в разных типах.
Вася Пупкин (2002-04-06 01:31:00) [35]Есть еще возможность (Delphi >=4)
В рамках одного класса можно иметь несколько одноименных методов.При обнаружении одноименного метода компилятор предупреждает, что у класса уже есть аналогичный метод с другими параметрами. Для подавления сообщений объявление метода можно сопровождать словом reintroduce.
Чтобы одноименные методы можно было отличить друг от друга, каждый из них должен иметь уникальный набор параметров.
lipskiy (2002-04-06 01:26:00) [36]Не-а, не пробовал.
Я это не умею - с variant, я его боюсь, он какой-то очень виртуальный.
Шутка.
Как это делается, ась?
Если мона - примерчик.
VID (2002-04-06 01:00:00) [37]а ты пробовал использовать тип VARIANT, а потом проводить проверку типа переменной, или ещё что-то в этом роде ?