Joe*_*out 5 c# c++ design-patterns
在C++中,我习惯使用sentry模式来确保在块或函数退出时正确释放所获取的资源(例如,参见此处).例如,我使用它来获取图形状态,然后我可以做任何我想要的状态,当sentry对象(引用)超出范围时它会被放回去.
现在我正在使用C#,同样的技巧不起作用,因为析构函数不会被调用,直到谁知道 - 以后.
是否有一些OTHER方法可以保证在释放对象的最后一个引用时触发?或者我只需要记住在从我将使用哨兵的任何方法返回之前调用一些Restore()或Apply()或DoYourThing()方法?
Dan*_*try 12
C#具有终结器,如C++,在对象被销毁时调用.它们与C++的形式相同,即:
~ClassName()
{
}
Run Code Online (Sandbox Code Playgroud)
如您所知,C#没有确定性的内存管理,因此这不是一个很好的保证.其直接结果是,你应该不使用终结在C#中释放非托管资源.相反,我们使用IDisposable界面.这会在实现者上公开单个方法,Dispose当您要释放非托管资源时,该方法将被调用.
public class MyDisposable : IDisposable
{
public void Dispose()
{
// get rid of some expensive unmanaged resource like a connection
}
}
Run Code Online (Sandbox Code Playgroud)
我们也可以使用using糖来允许块终止Dispose()时的语义调用using(优雅或不优雅).
using(var disposable = new MyDisposable)
{
// Do something with the disposable
} // Dispose is invoked here
Run Code Online (Sandbox Code Playgroud)
如果您发现自己使用终结器,并且 Dispose可以考虑使用该GC.SuppressFinalize方法,尽管这有点超出了我的范围.有一个很好的讨论,其他地方在计算器上这个位置
当然,这可以用来执行RAII-esque欺骗,例如
using(var guard = new Guard(resource))
{
}
Run Code Online (Sandbox Code Playgroud)
C#using为这种情况提供了块,它适用于任何实现IDisposable.
例如,如果您有一个类型class Foo : IDisposable,那么您可以这样做:
using (new Foo(/* ... */)) {
// Your code that depends on this resource.
}
Run Code Online (Sandbox Code Playgroud)
这相当于:
Foo x = new Foo(/* ... */);
try {
// Your code
} finally {
if (x != null) {
((IDisposable)x).Dispose();
}
}
Run Code Online (Sandbox Code Playgroud)
当然,除非您无权访问x. 但是,如果需要,您可以通过在using块中创建变量来获得此类访问权限:
using (Foo foo = new Foo(/* ... */)) {
// Your code that uses "foo"
}
Run Code Online (Sandbox Code Playgroud)
创建可以通过这种方式或由垃圾收集器处理的类的标准方法是:
class Foo : IDisposable {
protected virtual void Dispose(bool disposing) {
// Your cleanup code goes here.
}
public void Dispose() {
GC.SuppressFinalize(this);
Dispose(true);
}
~Foo() {
Dispose(false);
}
}
Run Code Online (Sandbox Code Playgroud)