The failed Daniel event delegate, with my delegate

Source: Internet
Author: User

Read the online Daniel's Delphi event commissioned, the actual use of a bug. The code is as follows:

Unit fadelegate;

Interface

uses
Generics.collections, Typinfo, Objauto, Sysutils;
type
Event = Class
private
Fmethods:tlist<tmethod>;
Finternaldispatcher:tmethod;
//the method of a generic class is not inline-assembled and can only be implemented by a non-generic parent class
Procedure Internalinvoke (params:pparameters; Stacksize:integer);
public
constructor Create;
destructor Destroy; override;
end;

Event<t> = Class (Event)
Private
Fobj:tobject;
fproname:string;

Fentry:t;
function Converttomethod (var Value): TMethod;
Procedure Setentry (var aentry);
Public
Constructor Create (Obj:tobject; proname:string);
destructor Destroy; Override
Procedure Add (amethod:t);
Procedure Remove (amethod:t);
function IndexOf (amethod:t): Integer;

Property Invok:t read Fentry;
End

Implementation

{event<t>}

Procedure Event<t>. ADD (amethod:t);
Var
M:tmethod;
Begin
M: = Converttomethod (Amethod);
if ((M.code<>nil) and (Fmethods.indexof (m) < 0) Then
Fmethods.add (m);
End

function Event<t>. Converttomethod (Var Value): TMethod;
Begin
Result: = TMethod (Value);
End

Constructor Event<t>. Create (Obj:tobject; proname:string);
Var
Methinfo:ptypeinfo;
Typedata:ptypedata;
M:tmethod;
P:pointer;
Begin
Methinfo: = TypeInfo (T);
If methinfo^. Kind <> Tkmethod then//detection T type
Raise Exception.create (' T is Method (Member function)! ');

Typedata: = Gettypedata (Methinfo);

Inherited Create ();
Finternaldispatcher: = Createmethodpointer (Internalinvoke, typedata); Convert the Internalinvoke function address to TMethod
Setentry (Fentry); Fentry is the entry address, set to Finternaldispatcher

Fobj:=obj;
Fproname:=proname;

M:=getmethodprop (Fobj,fproname);
P:[email protected];
ADD (T (p^)); Add the original method of the object first
Setmethodprop (Fobj,fproname,finternaldispatcher); Set the entry of the object
End

destructor Event<t>. Destroy;
Begin
Releasemethodpointer (Finternaldispatcher); And Createmethodpointer is a pair, just the opposite.

Inherited Destroy;
End

function Event<t>. IndexOf (amethod:t): Integer;
Begin
Result: = Fmethods.indexof (Converttomethod (Amethod));
End

Procedure Event<t>. Remove (amethod:t);
Begin
Fmethods.remove (Converttomethod (Amethod));
End

Procedure Event<t>. Setentry (var aentry);
Begin
TMethod (aentry): = Finternaldispatcher;
End

{Event}

Constructor Event.create;
Begin
Fmethods: = Tlist<tmethod>. Create;
End

destructor Event.destroy;
Begin
Fmethods.free;
Inherited Destroy;
End

procedure Event.internalinvoke (params:pparameters; Stacksize:integer);
var
Lmethod:tmethod;
begin
For Lmethod in Fmethods do
begin
//If the stack is used (that is, the Register convention parameter is greater than 2 or the STDCALL,CDECL Convention), all the data in the stack is copied into the parameter stack
if StackSize > 0 Then
ASM
MOV ecx,stacksize The third parameter of//move and prepares for the next sub ESP
SUB esp,ecx//Stack top-StackSize (stack is negative)
MOV Edx,esp//move the second parameter
MOV Eax,params
LEA Eax,[eax]. TPARAMETERS.STACK[8]//move the first parameter
Call System.move
end;
//register agreement to fill in three registers, eax must be self, if the other protocol register is not affected by the completion of
ASM
MOV eax,params//The Params read to EAX
MOV Edx,[eax]. Tparameters.registers.dword[0]//edx
MOV Ecx,[eax]. TPARAMETERS.REGISTERS.DWORD[4]//eax

MOV eax,lmethod.data//put Method.data to EAX, if it is the Register convention is self. otherwise it doesn't.
Call lmethod.code//calls Method.data
End
End
End

Bug experience assigning a value to the value parameter can be an error when delegating to the event Onupdatedata of a column in Tdbgrideh! Dizzy, do not know how to do well! So have to use their own method to solve!

My event delegate:

Delegate<t>=class
Private
I:integer;
Fentrance:tmethod;
Protected
Delegates:array of TMethod;
Procedure Addmethod (M:tmethod);
function getruneof (): Boolean;
function Getrun (): T;
Public
Constructor Create (C:tobject; proname:string); virtual;
destructor Destroy; Override
Procedure Add (delegate:t);

End

Denotify=class (delegate<tnotifyevent>)
Published
Procedure Dorun (Sender:tobject);
End

Implementation


Procedure Delegate<t>. ADD (delegate:t);
var M:tmethod;
P:pointer;
Begin
P:[email protected];
M:=tmethod (p^);
Addmethod (TMethod (p^));
End

Procedure Delegate<t>. Addmethod (M:tmethod);
Begin
if ((M.code=nil) or (M.data=nil)) then exit;
if (M.code<>fentrance.code) THEN BEGIN
SetLength (Delegates,high (Delegates) +2);
Delegates[high (Delegates)]:=m;
End
End

Constructor Delegate<t>. Create (C:tobject; proname:string);
Begin
fentrance.data:=self;
Fentrance.code:=methodaddress (' Dorun ');

Addmethod (Getmethodprop (c,proname));
Setmethodprop (c,proname,fentrance);
i:=0;

If Assigned (lstdelegates) =false then BEGIN
Lstdelegates:=tlist.create;
Lstdelegates.add (self);
End
End


destructor Delegate<t>. Destroy;
Begin
Dec (itotal);
If Lstdelegates.count=0 Then
Lstdelegates.free
Else
Lstdelegates.delete (Lstdelegates.indexof (self));

inherited;
End

function Delegate<t>. Getrun:t;
var M:tmethod;
P:pointer;
Begin
M:=DELEGATES[I-1];
P:[email protected];
Result:=t (p^);
End

function Delegate<t>. Getruneof:boolean;
Begin
Result:=not (I<=high (delegates));
If Result=false Then
INC (i)
Else
i:=0;
End


Procedure Denotify.dorun (Sender:tobject);
Begin
While not getruneof () does
Getrun () (Sender);
End

This method has a great disadvantage, that is, an event type to derive a class! But really, there's no problem.

It seems that things have two sides, concentrated very large code, it is very skilled, very difficult, and will be more error-prone.

If you concentrate small code, the skills required are not much, easy to understand, but more redundant. Upset.

However, in any case, the right is the first. It's not good to be any more skillful. The first method seems very powerful, but there are bugs, do not know how to change, because too advanced ....

The failed Daniel event delegate, with my delegate

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.