如何将未知接口保存到指针



我可以将未知接口保存到指针吗?

例如,我有一个未知接口,想将其保存到树节点数据?

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
...  

接口是指针,因此可以按原样存储(不要使用@运算符)。然而,为了确保接口的寿命,只要节点引用它,就必须手动增加/减少它的引用计数,例如:

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;

您需要捕获接口引用的值,而不是保存引用的变量的地址。

所以,这样做吧:

Node.Data := Pointer(X);
....
X := IInterface(Node.Data); 
// use IInterface in preference to IUnknown

但您必须确保正确处理引用计数,因为此强制转换会破坏自动引用计数。

因此,当您将接口放入Node时,请参考:

Node.Data := Pointer(X);
X._AddRef;

并在修改Node.Data或销毁节点时调用_Release


正如您所发现的,这相当混乱,而且很容易出错。解决这个问题的更好方法是让编译器来做这项工作。定义TTreeNode的子类,并使树视图使用该子类。忽略节点的Data属性,使用子类中引入的IInterface类型的属性。

实现这一点的方法是提供一个OnCreateNodeClass事件处理程序,它告诉树视图控件创建子类的节点,而不是普通的旧TTreeNode。这种技术的例子可以在这里找到:https://stackoverflow.com/a/25611921/

最新更新