Главная страница
    Top.Mail.Ru    Яндекс.Метрика
Форум: "Основная";
Текущий архив: 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
3-93793
Sergvc
2004-02-03 16:06
2004.02.29
список баз в SQL Server


14-94130
Andy BitOff
2004-02-09 02:59
2004.02.29
По рзелульаттам илссеовадний


1-94025
DelphiN!
2004-02-09 21:21
2004.02.29
Ошибка при перехвате ввода с клавиатуры в 9x


3-93762
Марат
2004-02-04 09:07
2004.02.29
Справочники


1-93970
semensoft
2004-02-17 14:09
2004.02.29
Изменение размеров jpg





Afrikaans Albanian Arabic Armenian Azerbaijani Basque Belarusian Bulgarian Catalan Chinese (Simplified) Chinese (Traditional) Croatian Czech Danish Dutch English Estonian Filipino Finnish French
Galician Georgian German Greek Haitian Creole Hebrew Hindi Hungarian Icelandic Indonesian Irish Italian Japanese Korean Latvian Lithuanian Macedonian Malay Maltese Norwegian
Persian Polish Portuguese Romanian Russian Serbian Slovak Slovenian Spanish Swahili Swedish Thai Turkish Ukrainian Urdu Vietnamese Welsh Yiddish Bengali Bosnian
Cebuano Esperanto Gujarati Hausa Hmong Igbo Javanese Kannada Khmer Lao Latin Maori Marathi Mongolian Nepali Punjabi Somali Tamil Telugu Yoruba
Zulu
Английский Французский Немецкий Итальянский Португальский Русский Испанский