2

我有各种包装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每次都返回一个新的,我可以查一下。但这会带来线程问题,对吧?

有没有更好的办法?

4

3 回答 3

1

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

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

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

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

于 2009-12-28T08:57:55.077 回答
1

整个代码看起来不正确。

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

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

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

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

于 2009-12-28T09:21:13.127 回答
0

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

于 2009-12-28T09:02:46.533 回答