如何在C#中做Sentry模式?

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)


cdh*_*wie 4

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)