C# 实现IDisposable的类是否有方法在遇到异常时抛出异常';是否未通过using块实例化?

C# 实现IDisposable的类是否有方法在遇到异常时抛出异常';是否未通过using块实例化?,c#,idisposable,C#,Idisposable,我发现了一些潜在的危险类,如果它们不能被实例化,那么它们的危险性就会大大降低,除非它们是在using语句中实例化的 我想知道是否有一种方法可以强制类仅以这种方式实例化 (我知道IL编译出来的是什么,这就是为什么我不确定这是否可能的原因) 干杯 菲尔。为了所有有效的目的,这是不可能的。特别是因为它不必是使用的,有人可以写出try{}finally{}。您可以确保在终结器中正确地处理了任何未被管理的内容。没有办法强制执行它,但您可能可以构建一个标记它的方法。不,没有这样的方法,因为using语句是静

我发现了一些潜在的危险类,如果它们不能被实例化,那么它们的危险性就会大大降低,除非它们是在using语句中实例化的

我想知道是否有一种方法可以强制类仅以这种方式实例化

(我知道IL编译出来的是什么,这就是为什么我不确定这是否可能的原因)

干杯


菲尔。

为了所有有效的目的,这是不可能的。特别是因为它不必是使用的
,有人可以写出
try{}finally{}
。您可以确保在终结器中正确地处理了任何未被管理的内容。

没有办法强制执行它,但您可能可以构建一个标记它的方法。

不,没有这样的方法,因为
using
语句是静态的。

不,不是真的-这对开发人员来说确实是一种干扰。我认为您正在寻找的是一个静态分析工具,如FxCop,以确保一次性对象得到正确处理。

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

如果您的类实现正确,那么析构函数应该清理所有非托管的、未分解的资源。这不太理想,但仍然可以工作


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

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

您应该做的是在类中实现,以便正确地清理它们

我见过的一个技巧(事实上我自己也用过)是在对象构造期间记录调用堆栈,然后在析构函数中使用Debug.Assert,在创建对象时通知开发人员调用堆栈。这对追踪未处置物体的来源有很大帮助,因此有助于找到负责处置的物体没有这样做的地方。大致如下(我无法访问我使用的代码,因此这是我目前的最佳猜测,YMMV):


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

尽管您不能强制客户机使用
语句编写
,但您可以将资源封装在使用
using
语句的方法中。这将是您的资源代码:

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

,并通过静态代码分析对此进行说明。只需将这些规则配置为导致错误,就会导致编译时失败。为什么还要等到运行时才出现异常?

我不相信有问题的开发人员每次都能正确处理这个问题-这就是我在强制执行之后的原因。@Phil:没有办法让编译器来做,但在部署之前有可能捕获它。@Phil那么我认为你需要更好的开发人员,因为有时候,当你有一个catch块的时候,仅仅使用
try{}catch{}finally{}
使用{try{}catch{}
或者
try{using{}catch{}
更方便。如果你除了在finally block中处理之外还需要做一些事情,那么它也会更方便。FxCop和nitiq也可以用于这种规则执行。这是我见过的最好的建议。我认为您可以在每个解决方案的基础上实施代码分析。这不对吗?@Jaxidian-我不确定解决方案级别,我知道在构建每个项目时可以运行CA。但它会输出警告。在使用Team System时,您可以在签入过程中执行此操作。@Jaxidian-看起来解决方案设置只是为CA设置了项目级属性。尽管如此,有时您明确不希望立即处置对象。有时您需要存储它,在这些情况下,这可能会在调试期间为通知提供一个假阳性。我发现,在构建时记录堆栈跟踪有助于跟踪违规对象的创建位置以及它应该被处置的位置。请注意,这并不总是有效的,在小程序中,垃圾收集器可以完全跳过使用终结器。您可以在一个小控制台应用程序中测试此行为,这只生成一次性类的单个实例。我确信它在
MSDN
;-)的某个地方提到过我建议编写一个类,该类将连接到放置在开发人员下的电子设备,而开发人员不会自己清理。然后,您可以实现一个终结器,该终结器检查是否调用了dispose,如果没有调用,则对开发人员进行电击。我想这叫做巴甫洛夫反射诱导。
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 the resource...
});