如何避免在整个地方创建新的包装器对象?

时间:2009-12-28 08:49:40

标签: c# pointers reference wrapper intptr

我有各种包装IntPtr的类。它们不存储自己的数据(指针除外),而是使用属性和方法使用非托管库公开指针处的数据。它运行良好,但我已经达到了我需要能够从其他包装器对象引用这些包装器对象的程度。例如:

public class Node {
    private IntPtr _ptr;

    public Node Parent {
        get { return new Node(UnmanagedApi.GetParent(_ptr)); }
    }

    internal Node(IntPtr ptr) {
        _ptr = ptr;
    }
}

现在,我可以简单地返回一个new Node(parentPtr)(如上所述),但是有可能拥有数万个节点。这不是一个坏主意,因为多个包装器对象可能最终引用相同的IntPtr

我该怎么做才能解决这个问题?我想过使用静态KeyedCollection类,它使用每个IntPtr作为键。因此,我不是每次都返回一个新的Node,而是可以查找它。但这会带来线程问题,对吗?

有更好的方法吗?

3 个答案:

答案 0 :(得分:1)

我能看到的最大问题是谁负责删除指针引用的对象?

重用同一个对象不一定是线程问题,但如果你负责在非托管对象上调用delete,你需要在对象中实现某种引用计数。

如果对象是只读对象,则使用具有相同指针的多个对象可能会更容易。如果它们具有可以更改的状态,那么如果多个对象持有指向该状态的指针,则需要了解进行更改的影响。

您可能还想查看C ++ / CLI(托管C ++)以在C#和非托管库之间提供一个层,并在那里进行翻译/操作的艰苦工作,并为C#提供更简单的API。

答案 1 :(得分:1)

这整个代码看起来不正确。

您对GetParent函数的使用似乎暗示您具有树状结构。让我对你的代码做一些猜测,他们可能是错的。

  1. 您希望广泛使用UnmanagedAPI,并且不希望在.NET代码中复制此代码。

  2. 您只是想通过访问未损坏的代码来确保不会出现内存问题。

  3. 我建议您不是逐个节点地创建.NET代码,而是为整个树/图结构创建.NET包装器,并提供可以将非托管API指针作为参数传递的.NET API,但严格处理分配/释放,以避免内存问题。这将避免不必要地分配新的内存结构,只是为了分配已经存在的东西,即GetParent函数。

答案 2 :(得分:0)

我有一个相关的问题。删除非托管对象是明确完成的。所以我所做的是为包含可用包装器实例的静态字典的所有包装器创建一个基类。对象在构造函数中添加到字典中,并在WrapperBase.Delete()方法中删除。请注意,为此类方法使用显式的Delete()方法很重要 - 否则GC将永远不会因为静态字典的引用而释放包装器实例。