Top.Mail.Ru
Мастера DELPHI, Delphi programming community Титульная страница Поиск, карта сайта Написать письмо 
| Новости | Поиск | FAQ | Статьи | Книги | Новости VCL |
| Форумы ЧАТ | Орешник | KOL и MCK |
Форумы -» Основная («Начинающим»)/ Базы / WinAPI / Компоненты / Сети / Media / Игры / Corba и COM / KOL / FreePascal / .Net / Прочее / RSDN.ORG

« предыдущая ветвь | форум | следующая ветвь »

Как описать входной параметр процедуры многовариантно?


Страницы:   1 2

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.


Страницы:   1 2

Наверх

Титульная страница Поиск, карта сайта Написать письмо