![]() |
| ||
|
|
Новости |
Поиск |
FAQ |
Статьи |
Книги |
Новости VCL
| | Форумы ЧАТ |
Орешник |
|
| |||
| |||
« предыдущая ветвь | форум | следующая ветвь »
Как описать входной параметр процедуры многовариантно?
lipskiy © (2002-04-05 21:43:00)Ребята, я тут уже спрашивал, как можно описать входной параметр процедуры в мультивариантном виде, мне предложили использовать перегрузку. Но при перегрузке надо описывать два тела процедур, а если они объемные и почти одинаковые, отличаются только несколькими строчками, то описывать дважды одно и то же не хочется.
Может быть есть все-таки вариант описания входного параметра в виде списка возможных типов?
Конкретно мне нужно следующее:
proceudre Some(Input:String);
proceudre Some(Input:TStringList);
Параметр Input мне нужно описать так, чтобы при вызове ОДНОЙ процедуры Some можно было задать или String, или TStringList.
Как это сделать?
lipskiy (2002-04-16 01:26:00) [1]Ладно, ок, понял я все варианты, спасибо.
Этот тоже хорош, но структура моего конкретного случая немного сложнее, поэтому там это менее удобно.
Ладно, ребята, закроем эту ветку, а? :)
Всем спасибо!
IGOREK (2002-04-15 02:30:00) [2]Все таки перезагрузка вещь хорошая.
Посмотрел историю обсуждения, и нашел, что тебе надо передавать
то String, то StringList.
Предлагаю такой вариант (может где ошибки - не компилировал):
procedure f1(FileName: TString)
var
SL: TStringList;
begin
SL.Lines.Add(FileName);
f2(SL);
end
procedure f2(var SL: TStringList)
begin
//общий код
if SL.Lines.Count = 0 then
//код для записи в SL
else
//код для записи в файл
//общий код
end
Может так тебе понравится ;-)
lipskiy (2002-04-14 19:14:00) [3]Да неудобно это!
Вот структура:
begin
// много общего кода
// ветвление в зависимости от входного параметра
if (input is string) then
// много кода по одной ветке
else
// много кода по другой ветке
// и снова много общего кода
end;
Куда деть начальный и конечный общий код?
Да и нижний общий код увязан с ветвящимся, то есть надо тогда делать группу взаимоувязанных процедур.
Это возможно, но просто неудобно!
IGOREK (2002-04-14 15:04:00) [4]Может я не вник в суть проблемы, но я обычно в таких ситуациях делаю так (все таки перегруженные процедуры):
одна процедура главная (т.е. она содержит весь основной код) принимает один параметр;
вторая процедура использует первую, предварительно преобразовывая свой параметр к типу параметра первой.
Если они должны делать одинаковые вещи, то и параметры должны преобразовываться один в другой.
А если различные типы параметров влекут за собой различный код, то соответственно этим процедуры и будут отличаться - можно разнести такие участки кода в две разные процедуры или сделать одну универсальную.
lipskiy (2002-04-13 22:33:00) [5]Перегружаемые функции требуют описания двух тел. Это неудобно в данном случае и про такой вариант я и сам знаю. Вопрос был именно для одного входного параметра одной процедуры.
У меня большая прецедура, ветвление где-то в середине, и что, мне дублировать ее дважды?
Имхо, лучшее решение, коим я и воспользовался - два входных параметра разного типа, один из которых задан, другой пустой (MBo © (06.04.02 17:20)).
Fantasist (2002-04-12 17:39:00) [6]
> Какой вы продвинутый программист
> А если надо оптимизировать на время выполнения, то перегружаемые
> функции не подойдут. Как и многие здешние варианты.
Как это? Перегружаемые функции и есть самая хорошая оптимизация по времени исполнения - все определяется на момент компиляции.
Бурундук (2002-04-12 12:20:00) [7]PVOzerski ©
cpp esse delendam :)
SPeller (2002-04-12 12:13:00) [8]ivv © (12.04.02 06:55)
Какой вы продвинутый программист
А если надо оптимизировать на время выполнения, то перегружаемые функции не подойдут. Как и многие здешние варианты.
PVOzerski (2002-04-12 11:44:00) [9]Резюмирую: плохо в OP без макросов...
REA (2002-04-12 11:19:00) [10]Выражаю солидарность с ivv
ivv (2002-04-12 06:55:00) [11]зачем измачиваца и делать отстой?
в опп есть перегружемые ф-ции - надо юзать их, а не страдать всякой х.....
lipskiy (2002-04-06 21:40:00) [12]:)
Я уже ровно так и сделал :)
Но все равно, спасибо.
SPeller (2002-04-06 17:47:00) [13]По-моему, будет проще, легче, логичнее, нагляднее и быстрее сделать так, как предложил MBo © (06.04.02 17:20). Так можно будет и сохранить в файл и одновременно в стринглист, чтобы не вызывать несколько раз. Просто поставить условия в теле процедуры, мол если то-то, то в стринглист, а если то-то, то в файл.
MBo (2002-04-06 17:20:00) [14]Procedure DownLoad (Receiver:TStringList;Fname:String="");
вызов 1
Download(nil,"e:\qq.txt");
вызов 2
Download(Stringlist1);
в теле
If Fname="" then receiver заполняем
можно и без default параметра String="", тогда
2) Download(Stringlist1,"");
lipskiy (2002-04-06 13:24:00) [15]ВАУ! Ребята! Всю ночь работали :) Спасибо всем!
Но все вроде не совсем то, хотя некоторые мысли надо попробовать, если, конечно проще никак.
Постановка задачи, более конкретно, такая.
Есть процедура, которая скачивает с инета один ресурс.
Этот ресурс может быть скачан и сохранен двумя способами - записан в файл на диск или загружен в StringList как текстовик.
В зависимости от способа сохранения я вызываю процедуру с одним из двух возможных параметров:
Receiver:String;
или
Receiver:TStringList;
В первом случае Receiver содержит имя файла на диске, в который будет записан скачанный файл.
Во втором случае Receiver содержит StringList, в который будут загружены строки скачанного текстового файла.
Есть также компонент закачки, его экземпляр называется HttpGet.
Он закачивает ресурс в свой поток, создание которого я вызываю в этой процедуре.
Тело процедуры должно быть одно, выглядеть она должна примерно так:
procedure DownLoad (Receiver:{что-то многовариантное});
var ToList:boolean;
FName:string; // имя приемника
DataIn : TStream;
begin
// Определяем тип сохранения закачанных данных
ToList:= Receiver is TStringList;
}
некоторый подготовительный код, который не хочется дублировать в двух телах процедур
}
if ToList then FName:= HttpGet.DocName // генерирует сам компонент закачки
else FName:= Receiver; // берется входное значение
// создем поток для закачки
HttpGet.RcvdStream:= TFileStream.Create(FName, fmCreate);
HttpGet.Get; // закачиваем
if ToList then // грузим данные в стринглист
begin
DataIn:= TFileStream.Create(FName, fmOpenRead);
Receiver.LoadFromStream(DataIn);
DataIn.Free;
end;
// иначе данные сохранились в файл с именем Receiver.
HttpGet.RcvdStream.Free;
}
некоторый завершающий код, который не хочется дублировать в двух телах процедур
}
end;
Это не рабочий вариант - писал только тут для объяснения логики.
Ну чего? Мне бы простенько как нибудь воткнуть входной параметр, и все. Если никак, то мне проще объявить два входных параметра и один флажок - какой на самом деле активный, это хоть и некрасиво, но все таки проще предложенных пока вариантов.
Вася Пупкин (2002-04-06 12:37:00) [16]>Bachin © (06.04.02 12:04)Я не утверждаю, что код Fantasist (06.04.02 06:56)не будет компилироваться.
Факт - что если этот код ( без изменений) откомпилировать в D5,то работать не будет.
Bachin (2002-04-06 12:04:00) [17]2 Вася Пупкин © (06.04.02 09:50)
Делфи 5,6 тут ни при чем!
Почитай как работать с вариантами.
Это пройдет и на Делфи 3 (проверено).
2 All
Если бы точно знать постановку задачи -
можно было бы о чем-то говорить. В большинстве случаев (думаю похожих)
если не надо возвращать в эту переменную параметр отлично подходит
TVarRec.
Типа:
function BindParamArray( HStmt : THStmt;
const BindArray : array of const ) : boolean;
var
Index: integer;
begin
for Index := 0 to High(BindArray) do
begin
case BindArray[Index].VType of
vtInteger: begin
...................
ну и вызов
BindParamArray( ..., [111])
BindParamArray( ..., ["String"])
BindParamArray( ..., [111, "String", 11.25, DateTime])
...................
Вася Пупкин (2002-04-06 09:50:00) [18]2 Fantasist (06.04.02 09:02)В Delphi 6 действительно будет работать, но в Delphi 5 выдаст "Invalid variant operation"...
Fantasist (2002-04-06 09:02:00) [19]
> А Вы пробовали это запустить ?
> Вся беда в том, что variant не может содержать ссілку на
> данные типа Pointer или class... боюсь, тут придется несколько
> больше "извращаться" :(
Вот сейчас попробывал. Работает. Кто вам сказал, что pointer туда записывать нельзя? А на кой тогда ByRef?
В крайем случае, если в какой-то версии это все-таки не поддерживается(со стандартом не сверялся), можно затолкать это как Integer.
Вася Пупкин (2002-04-06 08:04:00) [20]А вот так - пожалуйста :)
...
type
TForm1 = class(TForm)
Button1: TButton;
Label1: TLabel;
Button2: TButton;
procedure Button1Click(Sender: TObject);
procedure Button2Click(Sender: TObject);
end;
var
Form1: TForm1;
implementation
{$R *.DFM}
procedure sm(vr: array of const);
begin
if vr[0].VType=VtObject then
begin
(vr[0].VObject as TButton).Caption:="t"
end
else
Form1.Label1.Caption:=String(vr[0].VPChar);
end;
procedure TForm1.Button1Click(Sender: TObject);
begin
sm([Sender]);
end;
procedure TForm1.Button2Click(Sender: TObject);
begin
sm(["O-o-p-s"]);
end;
end.