[delphi] скастить procedure of oject в procedure

kill-still

есть типы
TItrerationTask = procedure(aDataSet: TADODataSet);
TItrerationTaskOfObject = procedure (aDataSet: TADODataSet) of object;
как перегрузить процедуру, использующую один из этих типов так, чтобы не писать тело дважды?
procedure ForEachRecord(aDataSet: TADODataSet; aPerform: TItrerationTask);
....
begin
...
aPerform(aDataSet);
...
end;
по идее так:
procedure ForEachRecord(aDataSet: TADODataSet; aPerform: TItrerationTaskOfObject);
begin
ForEachRecord(aDataSet, TItrerationTask(TMethod(aPerform).Code;
end;
но что-то оно падает при касте.
может кто в курсе?

Serab

А ничего, что of object'у нужен Self? Откуда он его возьмет?
В .NET это решается поддержкой делегатов в языке. В C++ можно намутить функторов. Как в Delphi — хз.

kill-still

Бля, точно. А если наоборот (в TItrerationTaskOfObject подсунуть (nil, aPerform) )?
просто не охота копипастой заниматься.

Serab

Кстати, я тут почитал, оказывается procedure of object — это и есть типа делегат, т.е. она сам объект тоже помнит. Тогда хз почему не преобразуется. А зачем там дописывается TMethod, .Code, напрямую не скастится?

kill-still

напрямую оно упадёт переполнением стека, т.к. сама себя будет вызывать :)
с принудительным кастом
ForEachRecord(aDataSet, TItrerationTaskOfObject(aPerform;
не компилится:
[Pascal Fatal Error]: F2084 Internal Error: C4989
при попытке обмануть таким образом:
var
tmpMethod: TMethod;
begin
tmpMethod.Code := @aPerform;
ForEachRecord(aDataSet, TItrerationTaskOfObject(tmpMethod;
end;
падает

kill-still

О, гениальное в своей простоте читерство =)

Serab

а у меня связанный с этим читерством вопрос: в делфи что, нельзя создать временный объект? Т.е. там чувак в начале приводит нормальное решение, а потом долго извращается с удалением этого объекта.

kill-still

не слышал никогда про временные объекты в делфи.
чтобы не заботится о памяти в делфи есть 2 подхода к автоматизации применить:
1) наследовать от TComponent:

TGProc = procedure;
TMProc = procedure of object;
class TWGP = class(TComponent)
fgp : TGProc;
constructor Create(AOwner: TComponent; gp: TGProc); override;
procedure ptr;
end;

constructor TWGP.Create(AOwner: TComponent; gp: TGProc);
begin
inherited Create;
fgp := gp;
end;

procedure TWGP.ptr;
begin
fgp;
end;
.....
CallMe(TWGP.Create(SomeObj, GlobalThing).ptr);

тогда оно само сдохнет, когда будет SomeObj дестроится
2) наследовать от TInterfacedObject и повесить на интерфейс:

Iptr = Interface
procedure ptr;
end;

TGProc = procedure;
TMProc = procedure of object;
class TWGP = class(TInterfacedObject, Iptr )
fgp : TGProc;
constructor Create(AOwner: TComponent; gp: TGProc); override;
procedure ptr;
end;

constructor TWGP.Create(AOwner: TComponent; gp: TGProc);
begin
inherited Create;
fgp := gp;
end;

procedure TWGP.ptr;
begin
fgp;
end;
....
CallMe(Iptr(TWGP.Create(GlobalThing.ptr);

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

zorin29

В свое время я был приятно удивлен тем, что СТАТИЧЕСКИЕ методы класса подпадают под тип procedure of object. После обретения этого знания я перестал использовать глобальные процедуры, а стал использовать статические методы.
Так что, если тебе это позволено, рекомендую.

kill-still

Вообще-то я их туда и пихаю. :grin: :o
А сейчас вот возникла необходимость глобальную процедуру туда скормить.
Жаль что с локальной процедурой финт не проходит - она при попытке доступа к локальным переменным процедуры-родителя падает. Хотя конечно можно в параметрах передать нужное, но это неудобно - слишком много где по тексту придётся сигнатуры менять у этой штуки, которую я перегрузил.

kill-still

Такой вопрос: а шаблонные функции и функция, аргументы у которой - генерики, это одно и то же?

Serab

Так эту проблему решает то же самое читерство, параметры сохраняешь в полях того объекта.

kill-still

какого объекта? голая процедура.
З.Ы. только не надо предлагать сохранять в глобальных переменных. :)
глобальные переменные - зло.

Serab

В TWGP свой добавь поля, соответствующие дополнительным параметрам, сигнатура процедуры в нем останется старой. Необходимые конкретные значения параметров передавай в конструктор.
З.Ы. только не надо предлагать сохранять в глобальных переменных. :)
глобальные переменные - зло.
это ты об этом подумал.
Оставить комментарий
Имя или ник:
Комментарий: