如何从C#确定性地处理托管C ++ / CLI对象?

时间:2011-02-08 15:48:00

标签: c# interop c++-cli

我在C ++ / CLI程序集中有一个托管对象。作为C ++ / CLI,它通过“析构函数”实现Disposable模式(是的,我知道它与标准C ++析构函数不同)。从C ++ / CLI,我只需delete对象。但是,我将此对象用作C#类中的成员变量。

从我的C#类开始,当我使用它时,我想调用C ++ / CLI对象上的Dispose()方法的等效方法。由于它是(并且必须是)类的成员变量,因此使用using()块是不可能的。据我所知,没有公开的方法可以直接,确定地处理来自C ++ / CLI之外的语言的资源。我怎么能做到这一点?

3 个答案:

答案 0 :(得分:10)

在C ++ / CLI中并不是那么明显,但它在C#中的运行方式完全 。使用对象浏览器查看类时,您可以看到它。或者像ildasm.exe这样的反编译器,是查看它的最佳方式。

编写析构函数时,C ++ / CLI编译器会自动生成一堆代码。它实现了一次性模式,你的类自动实现IDisposable,即使你没有这样声明它。你得到一个公共的Dispose()方法,一个受保护的Dispose(bool)方法和一个自动调用GC :: SuppressFinalize()。

您在C ++ / CLI中使用delete来显式调用它,编译器会发出Dispose()调用。通过使用堆栈语义,您可以在C ++ / CLI中获得等效的RAII,编译器会自动在范围块的末尾发出Dispose调用。 C ++程序员熟悉的语法和行为。

如果该类是用C#编写的,那么您在C#中执行的操作与C#完全相同。您可以调用Dispose()来显式调用,使用using语句以异常安全的方式隐式调用它。

相同的规则另外适用,当您需要释放非托管内存的东西时,您只需要需要析构函数。几乎总是一个本机对象,即在构造函数中分配的对象。如果非托管对象很小并且GC :: AddMemoryPressure()是一个非常不错的替代方案,请考虑它可能不值得。但是,您必须在这样的包装类中实现终结器(!ClassName())。您不能强制外部客户端代码调用Dispose(),这样做是可选的,并且经常被遗忘。您不希望这种疏忽导致非托管内存泄漏,终结器确保它仍然被释放。通常,编写析构函数的最简单方法是显式调用终结器(this->!ClassName();

答案 1 :(得分:9)

类似C ++ / CLI析构函数的语法会自动实现IDisposable,但它的表现方式类似于C#的explicit interface implementation。这意味着您必须转发IDisposable才能访问Dispose方法:

((IDisposable)obj).Dispose();

答案 2 :(得分:-3)

你做不到。至少,不是来自C#。让垃圾收集器完成它的工作。