我可以将未知接口保存到指针吗?
例如,我有一个未知的接口,并希望将其保存到TreeNode数据?
var
X : Inknown;
保存:
....
Node:=TreeView1.Items.Add;
//Node.data:=x; //compiler won't allow this
Node.data:=@x;
...
获得:
...
var
//X:=Node.data; //compiler won't allow this too
Pointer(X):=Node.data; //an exception caught
...
答案 0 :(得分:12)
接口是指针,因此您可以按原样存储它(不要使用@
运算符)。但是,为了确保接口的生命周期,只要节点引用它,就必须手动递增/递减其引用计数,例如:
Node := TreeView1.Items.Add;
Node.Data := Pointer(x);
x._AddRef;
x := IUnknown(Node.Data);
procedure TMyForm.TreeView1Deletion(Sender: TObject; Node: TTreeNode);
begin
IUnknown(Node.Data)._Release;
end;
答案 1 :(得分:6)
您需要捕获接口引用的值,而不是保存引用的变量的地址。
所以,这样做:
Node.Data := Pointer(X);
....
X := IInterface(Node.Data);
// use IInterface in preference to IUnknown
但是你必须确保正确处理引用计数,因为这个转换会破坏自动引用计数。
因此,在将接口放入节点时请参考:
Node.Data := Pointer(X);
X._AddRef;
并在修改_Release
时调用Node.Data
,或销毁节点。
这是相当混乱的,容易出错,正如你发现的那样。解决问题的更好方法是让编译器完成工作。定义TTreeNode
的子类,并使树视图使用该子类。忽略节点的Data属性,并使用您在子类中引入的类型为IInterface
的属性。
实现这一目标的方法是提供一个OnCreateNodeClass
事件处理程序,该处理程序告诉树视图控件创建子类的节点而不是普通的TTreeNode
节点。可以在此处找到该技术的示例:https://stackoverflow.com/a/25611921/