我正在将一些代码从C ++ / CLI转换为C#。其中一个对象在C ++ / CLI版本中有一个析构函数。其他一些C ++ / CLI代码在使用后调用此对象的“删除”。
我需要在此对象的C#版本中实现哪种方法,以便那些“delete”继续运行相同的功能(IDisposable.Dispose,终结器或其他我不想要的东西)?
答案 0 :(得分:16)
如果您需要确定性地处理资源,我会说IDisposable
接口就是您所寻求的。这通常是非托管资源的情况,例如需要关闭的非托管句柄,流或数据库连接。
在C ++ / CLI中,如果声明托管类型(ref class
等),则使用析构函数语法实现IDisposable
,并使用{{调用Dispose()
1}}关键字。如果在本地声明托管类型的此类对象(不使用delete
运算符或^
),则当对象超出范围时,C ++ / CLI甚至会自动为您调用gcnew
。这样,C ++ / CLI比C#更方便。
使用C#时,您无法在对象上调用Dispose()
,而是需要手动调用delete
。处理Dispose()
对象的另一种方法是using
块。
终结器(使用析构函数语法在C#中实现)与C ++析构函数不同,因为它在调用时不确定。具有终结器的对象基本上排队,直到终结器线程决定调用它们的终结器,因此实际上你永远不知道何时调用它。
处理非托管资源的最佳方法可能是两者的结合。请参阅此处了解建议的方法:
http://msdn.microsoft.com/en-us/library/b1yfkh5e(v=vs.100).aspx
但请注意,使用IDisposable
时,即使您可以确定地处理非托管资源,仍然需要由垃圾收集器(非确定性地)收集托管对象。
我刚刚发现一篇文章解释了C ++ / CLI和C#之间的差异。你可能会觉得很有趣:
http://weblogs.thinktecture.com/cnagel/2006/04/ccli-finalize-and-dispose.html
答案 1 :(得分:4)
C ++ / CLI和C#之间存在术语不匹配。 C ++ / CLI析构函数(~Foo)是IDisposable.Dispose()方法实现。 C ++ / CLI类没有显式实现IDisposable,它只是存在析构函数而自动生成。
C ++ / CLI终结器(!Foo)是C#析构函数。
因此,C ++ / CLI delete 运算符等效于调用Dispose()方法。注意C ++ / CLI中的堆栈语义,由没有^ hat的引用类型的局部变量触发。编译器在作用域块的末尾生成对Dispose()的隐藏调用。这相当于使用关键字的C#。很难从源代码中看到,所以要特别注意或者用ildasm.exe查看生成的IL
答案 2 :(得分:1)
C#不提供相同的工具,但它确实为您提供了模式:
如果您的dtor正在关闭流,取消链接指针或正确设置状态,那么我觉得IDisposable
界面非常合适:
// C#
void Dispose()
{
_stream.Close();
_ptr = null;
_running = false;
}
// with
obj.Dispose();
你无法强迫GC保持内存开放。有一些方法可以帮助GC了解可以和应该被释放的内容,请阅读http://msdn.microsoft.com/en-us/library/ee787088.aspx以获取更多信息。
请注意,使用IDisposable
期望您适当地调用Dispose()
方法。因此,您需要使用delete
代替每个Dispose()
。终结器的安全部分是当GC实际释放它时,它将被调用。但是,您无法自己调用终结器(因此,如果删除/处置的时间很重要,那么这不是正确的解决方案。)
答案 3 :(得分:0)
对我而言,这实际上取决于析构函数的作用。如果它正在执行类似释放非托管资源(例如SQL或文件连接)的操作,那么我将实现IDispose并在Dispose()方法中关闭连接。
如果它正在销毁不需要任何明确清理的其他对象,那么我只是将析构函数保留下来并让GC处理它。