有没有办法让一个实现IDisposable的类在没有通过using块实例化的情况下抛出异常?

时间:2011-03-31 17:39:03

标签: c# idisposable

我发现了一些有潜在危险的类,如果它们无法实例化,那么危险程度要小得多,除非它们是在using语句中完成的。

我想知道是否有办法强制这些类只能以这种方式实例化。

(我知道IL汇编了什么,这就是为什么我不能确定这是可能的)

干杯,

菲尔。

8 个答案:

答案 0 :(得分:13)

没有办法强制执行它,但您可以构建一个custom Code Analysis rule来标记它。

答案 1 :(得分:8)

不,没有办法让编译器强制执行此操作。在任何情况下,这样做都是危险的,因为有时候你想要以其他方式使用IDisposable类,比如将它们封装在第二个IDisposable类的实例中等等。

如果你的类被正确实现,那么析构函数应该清理任何不受管理的,未处理的资源。这不太理想,但仍然有效。

一个好的选择是让析构函数在调试期间引发异常或记录。这可以帮助您在测试和调试期间跟踪任何“错过”使用IDisposable不正确的情况。

答案 2 :(得分:5)

出于所有有效目的,这是不可能的。特别是因为它不一定是using,所以有人可能会写出try{}finally{}。您可以确保在终结器中正确处理任何未管理的内容。

答案 3 :(得分:3)

这样做会使您的对象仅在本地范围内可用。这意味着您无法安全地将其存储在类字段中,例如。

虽然您无法强制客户端编写using语句,但您可以将资源封装在使用using语句的方法中。这将是您的资源代码:

public sealed class Resource : IDisposable {
  private Resource() { }
  public void Dispose() { ... }
  public void Use(Action<Resource> action) {
    using (var resource = new Resource()) {
      action(resource);
    }
  }
}

现在,客户端代码被迫通过Resource方法使用Use

Resource.Use(resource => { 
  // use the resource...
});

答案 4 :(得分:2)

不,没有这种方式,因为using语句是语法糖。

答案 5 :(得分:2)

你真的不想要这个,虽然这似乎是一个好主意。这意味着您的实例只能具有局部范围,并且您不能将一次性对象传递给其他方法,或者将它们用作类中的字段变量。

您应该做的是在班级中实施dispose pattern,以便正确清理它们。

我见过的一个技巧(实际上是我自己使用的)是在对象构造期间注意调用堆栈,然后在析构函数中有一个Debug.Assert,它在创建对象时通知开发人员调用堆栈。这有助于追踪非处置对象的来源,从而帮助找到负责处置的对象没有这样做的地方。沿着这些方向的东西(我无法访问我使用的代码,所以这是我目前最好的猜测,YMMV):

private StackTrace m_stackAtConstruction;
private bool m_disposed;

public Constructor()
{
     m_stackAtConstruction = new StackTrace();
     m_disposed=false;
}

public void Dispose() 
{
    Dispose(true);

    // Use SupressFinalize in case a subclass
    // of this type implements a finalizer.
    GC.SuppressFinalize(this);      
}

protected virtual void Dispose(bool disposing)
{
    // If you need thread safety, use a lock around these 
    // operations, as well as in your methods that use the resource.
    if (!m_disposed)
    {
        if (disposing) {
            if (_resource != null)
                _resource.Dispose();

        }
        else
        {
             Console.WriteLine("Object not disposed correctly - Stack trace at construction was " + m_stackAtConstruction.ToString());
        }

        // Indicate that the instance has been disposed.
        _resource = null;
        _disposed = true;   
    }    
} 

答案 6 :(得分:1)

CA2000CA2202CA2213通过静态代码分析涵盖了这一点。只需配置这些规则就会导致错误,并且您将遇到编译时失败。为什么甚至等到运行时才会出现异常?

答案 7 :(得分:0)

不,不是真的 - 那对开发者来说真的很有侵略性。我认为您正在寻找的是静态分析工具,如FxCop,以确保一次性物品得到妥善处理。