Форум: "Основная";
Текущий архив: 2004.02.29;
Скачать: [xml.tar.bz2];
ВнизКак сравнить две переменные типа TNotifyEvent? Найти похожие ветки
← →
Defunct (2004-02-15 23:35) [0]Как получить имя/адрес владельца метода имея адрес метода?
Вот привожу простенький фрагмент программы, F1, F2 назначется один и тот же метод одного и того же класса, разных екземпляров. Теоретически F1<>F2, как это проверить? При запуске фрагмента, на экран выводится A1=A2.
...
TMyComponent = Class
X : Cardinal;
Constructor Create;Virtual;
Procedure StepForward(Sender:TObject);virtual;
End;
var F1,F2:TNotifyEvent;
A1,A2:Pointer;
C1,C2:TMyComponent;
Impementation
Constructor TMyComponent.Create;
Begin
End;
Procedure TMyComponent.StepForward;
Begin
Inc(X);
End;
procedure TForm1.FormCreate(Sender: TObject);
begin
C1 := TMyComponent.Create;
C2 := TMyComponent.Create;
F1:=C1.StepForward;
F2:=C2.StepForward;
A1:=Addr(F1);
A2:=Addr(F2);
If A1<>A2 then Application.MessageBox("A1<>A2","A1<>A2")
else Application.MessageBox("A1=A2","A1=A2");
end;
...
Дополение к вопросу:
http://delphimaster.net/view/1-1076871235/
2 модератор: просьба не закрывать обсуждение.
← →
Palladin (2004-02-15 23:53) [1]
> Как получить имя/адрес владельца метода имея адрес метода?
никак... метод принадлежит классу а не объекту.
← →
Юрий Зотов (2004-02-16 00:02) [2]> Palladin © (15.02.04 23:53) [1]
Это верно, но ведь Self откуда-то берется?
:о)
> Defunct © (15.02.04 23:35)
TMethod.Data - указывает на экземпляр объекта, для которого вызывается данный метод (а Code дает адрес самого метода).
type
TMyComponent = class(TComponent)
public
procedure StepForward(Sender: TObject); virtual;
end;
TForm1 = class(TForm)
Button1: TButton;
procedure Button1Click(Sender: TObject);
end;
var
Form1: TForm1;
procedure TMyComponent.StepForward(Sender: TObject);
begin
//
end;
procedure TForm1.Button1Click(Sender: TObject);
var
F1, F2: TNotifyEvent;
begin
F1 := TMyComponent.Create(Self).StepForward;
F2 := TMyComponent.Create(Self).StepForward;
Caption := Format("$%x $%x", [Integer(TMethod(F1).Data), Integer(TMethod(F2).Data)])
end;
← →
Defunct (2004-02-16 00:11) [3]Большое спасибо!
← →
Юрий Зотов (2004-02-16 00:12) [4]Вот так будет более наглядно:
procedure TMyComponent.StepForward(Sender: TObject);
begin
ShowMessage(Format("$%x", [Integer(Self)]))
end;
procedure TForm1.Button1Click(Sender: TObject);
var
F1, F2: TNotifyEvent;
begin
F1 := TMyComponent.Create(Self).StepForward;
F2 := TMyComponent.Create(Self).StepForward;
Caption := Format("$%x $%x", [Integer(TMethod(F1).Data), Integer(TMethod(F2).Data)]);
F1(nil); // Сравните число в ShowMessage c первым числом в Caption
F2(nil); // Сравните число в ShowMessage cо вторым числом в Caption
end;
← →
Palladin (2004-02-16 00:15) [5]
> Юрий Зотов © (16.02.04 00:02) [2]
:) передается при вызове...
если чесно я не допонял, что пытается сделать автор в вышеуказанном коде... self всегда доступен в теле метода, а сравнивать указатели на метод на предмет равности... хем... странное дело...
Буду очень рад если приведете пример практики использования TMethod.Data
← →
Defunct (2004-02-16 00:20) [6]Да да, эта часть уже сама собой понятна. Раз получили адрес Self, они будут идентичны.
ключ был здесь,
struct TMethod
{
void *Code;
void *Data;
};
еще раз, огромное спасибо за пример
← →
Defunct (2004-02-16 00:22) [7]Palladin © (16.02.04 00:15) [5]
Буду очень рад если приведете пример практики использования TMethod.Data
привожу:
http://delphimaster.net/view/1-1076871235/
В двух словах - список событий с временами запуска. Фильтрация одинаковых событий в очереди событий
← →
Юрий Зотов (2004-02-16 00:36) [8]> Palladin © (16.02.04 00:15) [5]
> self всегда доступен в теле метода
Это да, и мы даже знаем, что он передается неявным параметром. Но зададим себе вопрос - а ОТКУДА компилятор берет значение этого параметра при формировании кода вызова?
> пример практики использования TMethod.Data
Эмуляция событий. В проекте, где я сейчас участвую, используется на всю катушку.
← →
Palladin (2004-02-16 00:55) [9]Спасибо, надо будет взять на заметку это дело.
← →
Юрий Зотов (2004-02-16 01:11) [10]> Palladin © (16.02.04 00:55) [9]
Кстати - таким же образом можно назначить обработчиком события обычную процедуру вместо метода объекта.
procedure Proc(Self, Sender: TObject);
begin
ShowMessage(Self.ClassName)
end;
var
B: TButton;
M: TMethod;
begin
B := TButton.Create(nil);
try
M.Code := @Proc;
M.Data := B;
SetMethodProp(B, "OnClick", M); // uses TypInfo
B.Click
finally
B.Free
end
end;
← →
Palladin (2004-02-16 02:31) [11]Про этот финт я в курсе :) Вот чего не увидел так это практической ценности в TMethod и при разработке не использовал никогда. Не те задачи, однако...
← →
Defunct (2004-02-16 04:06) [12]Хм.. получается при создании процедурного типа
F = Procedure(Param1:..;Param2:..;.. ParamN:ParamType);
создается
Record
Code : Pointer;
Param1 : ..
Param2 : ..
..
ParamN : ParamType;
End;
Причем полей как таковых нет, они будут загружены в стек на момент запуска процедуры.
А если это будет..
Procedure Of Object
То в Record добавляется поле Data:Pointer;
Мда, теперь понятно почему неполучилось найти разницу при таком сравнении:
TMyComponent = Class
Constructor Create;Virtual;
Procedure StepForward(Sender:TObject);Virtual;
End;
MyArray = Array[1..2] of DWord;
Var
P1,P2 : ^MyArray;
F1,F2 : TNotifyEvent;
Constructor TMyComponent.Create;
Begin
End;
Procedure TMyComponent.StepForward;
Begin
End;
procedure TForm1.Button1Click(Sender: TObject);
begin
F1 := TMyComponent.Create.StepForward;
F2 := TMyComponent.Create.StepForward;
P1 := @F1;
P2 := @F2;
Caption := Format("%x:%x %x:%x",[P1^[1],P1^[2], P2^[1],P2^[2]]);
end;
Все же интересно, из какого источника компилятор заполняет поля Data.
← →
Alex Konshin (2004-02-16 08:50) [13]Он передается как неявный первый параметр.
Так как первый параметр передается в регистре EAX (не будетм углубляться в разные модели вызовов), то, соответственно, он там обычно и находится на входе в процедуру.
Могу привести еще один пример использования TMethod - вызов метода прародителя в обход перекрытия этого метода родителем.
Иногда это нужно.
Еще одно применение - реализация подобия reflection из Java, то вызов метода по имени.
← →
pasha_golub (2004-02-16 09:24) [14]Alex Konshin © (16.02.04 08:50) [13]
Приведите, приведите. Очень интересно.
← →
MBo (2004-02-16 09:35) [15]>pasha_golub
type
C1 = class
procedure Method1;virtual;
end;
type
C2 = class(C1)
procedure Method1;override;
end;
type
C3 = class(C2)
procedure Method1;override;
end;
procedure C3.Method1;
type
tproc=procedure of object;
var
m:tmethod;
begin
m.code:=@c1.method1;
m.data:=self;
TProc(m);
end;
← →
Alex Konshin (2004-02-16 09:50) [16]Фантазии не хватает?
Собственно, вызов ничем не отличается от вызова другого метода.
var
method : TMethod;
...
with TMethod(method) do
begin
Code := @TGrandParent.SomeMethod;
Data := Self;
end;
...
method(...);
← →
Alex Konshin (2004-02-16 09:53) [17]MBo © (16.02.04 09:35) [15]
TProc не нужен.
← →
Alex Konshin (2004-02-16 09:55) [18]Упс, был неправ.
Нужно было в объявлении написать так:
type
TProc = procedure(...) of object;
var
method : TProc; // :) ну пусть будет так
← →
pasha_golub (2004-02-16 10:01) [19]MBo © (16.02.04 09:35) [15]
Alex Konshin © (16.02.04 09:53) [17]
Спасибо, уже видел. А не чревато ли это?
← →
Alex Konshin (2004-02-16 10:08) [20]Чем чревато? Естественно, нужно понимать, что ты делаешь.
← →
pasha_golub (2004-02-16 10:10) [21]Alex Konshin © (16.02.04 10:08) [20]
Иногда одним пониманием от беды не спасешься. :-)
Страницы: 1 вся ветка
Форум: "Основная";
Текущий архив: 2004.02.29;
Скачать: [xml.tar.bz2];
Память: 0.5 MB
Время: 0.008 c