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

Jim*_*ans 12 c# interop c++-cli

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

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

Han*_*ant 11

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

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

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

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

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


R. *_*des 8

类似于C++/CLI析构函数的语法会自动实现IDisposable,但它以类似于C#的显式接口实现的方式实现.这意味着您必须转换IDisposable为访问该Dispose方法:

((IDisposable)obj).Dispose();
Run Code Online (Sandbox Code Playgroud)

  • 不要在家里尝试:你可以使用空的`using`语句而不是调用Dispose方法:`using(obj);`.但是请想想孩子们. (4认同)