當使用以下定義實作事件時,Spring4D 將添加和呼叫方法,但不會在被詢問時洗掉處理程式(使用 IEvent<TaskItemChangeEvent>.Remove(MyProc) ),因為它無法識別它。
{$M }
TaskItemChangeEvent = reference to procedure(const TaskItem: ITaskItem; Event: TTaskListEvent);
以下確實有效,但我不想被迫系結到一個物件。
{$M }
TaskItemChangeEvent = procedure(const TaskItem: ITaskItem; Event: TTaskListEvent) of Object;
我相信問題是 TEventBase.Remove 中的這一行作為對程序的參考不是 TMethod?
if TMethod(handlers[i]) = TMethod(handler) then
uj5u.com熱心網友回復:
原因是編譯器可能會在您添加和洗掉它們的位置之間創建匿名方法的不同實體。
看下面的代碼:
var
proc: TProc;
procedure Add(p: TProc);
begin
proc := p;
end;
procedure Remove(p: TProc);
begin
Writeln(PPointer(@proc)^ = PPointer(@p)^);
end;
procedure A;
var
p: TProc;
begin
p := procedure begin end;
Add(p);
Remove(p);
end;
procedure B;
begin
Add(procedure begin end);
Remove(procedure begin end);
end;
procedure C;
begin
Add(A);
Remove(A);
end;
begin
A;
B;
C;
Readln;
end.
您會注意到 inB并且C它會列印出來False,因為這兩個匿名方法被傳遞給彼此Add并且Remove彼此不同。雖然B很明顯C不是,但編譯器實際上將代碼轉換為:
procedure C;
begin
Add(procedure begin A(); end);
Remove(procedure begin A(); end);
end;
這意味著如果您想使用IEvent<>方法參考型別并且能夠洗掉,則需要保留您添加的參考,以便它們相等,從而能夠在呼叫Remove.
事實上,在TEventBase參考內部都被處理為TMethod與此無關 - 當傳遞匿名方法時,它被轉換為TMethod. 畢竟,匿名方法型別是由編譯器創建的物件支持的介面,這使得進行這種轉換成為可能,并導致有必要保留添加的參考以洗掉它。
轉載請註明出處,本文鏈接:https://www.uj5u.com/gongcheng/481123.html
