将类型转换为IDisposable - 为什么?

10

看到这个。为什么要显式地将其转换为IDisposable?这只是一种简写,以确保在退出using块时调用IDisposable吗?

using (proxy as IDisposable)
{
  string s = proxy.Stuff()                                    
}
3个回答

27

这种“技巧”,如果可以这样称呼它的话,很可能是由于proxy属于编译器无法验证真正实现了IDisposable接口的类型。

using指令的好处在于,如果它的参数为null,则在退出using语句所在作用域时不会调用Dispose

因此,你所展示的代码实际上是下面代码的简写:

var disposable = proxy as IDisposable;
try
{
    string s = proxy.Stuff();
}
finally
{
    if (disposable != null)
        disposable.Dispose();
}

换句话说,它表示“如果这个对象实现了IDisposable接口,在我完成以下代码块后,我需要对其进行处理。”


4

如果您从某个地方获取了一个proxy实例,它的静态类型没有实现IDisposable,但是您知道真正的类型可能会这样做,并且希望确保它将被处理,那么可能需要执行此操作。

public class Proxy : ISomeInterface, IDisposable
{
    ...
}

private ISomeInterface Create() { ... }

ISomeInterface proxy = Create();

//won't compile without `as`
using(proxy as IDisposable)
{
    ...
}

3

这是不必要的,因为using语句与IDisposable接口有明确的关联,根据MSDN文档

提供了一种方便的语法,以确保正确使用IDisposable对象。

编辑C#语言规范(第8.13节)提供了using语句语法糖的三种可能扩展:

形如的using语句:

using (ResourceType resource = expression) statement

当ResourceType是一个非空值类型时,它对应于三种可能的扩展。

{
   ResourceType resource = expression;
   try {
      statement;
   }
   finally {
      ((IDisposable)resource).Dispose();
   }
}

否则,当ResourceType是可空值类型或动态类型以外的引用类型时,扩展为。
{
   ResourceType resource = expression;
   try {
      statement;
   }
   finally {
      if (resource != null) ((IDisposable)resource).Dispose();
   }
}

否则,当ResourceType为动态时,扩展为
{
   ResourceType resource = expression;
   IDisposable d = (IDisposable)resource;
   try {
      statement;
   }
   finally {
      if (d != null) d.Dispose();
   }
}

请注意,在这些扩展中,每个扩展都会进行强制类型转换,因此如最初所述,as IDisposable 是不必要的。

3
如果“代理”是程序员“知道”实现了IDisposable接口的对象,但编译器无法验证,那么为什么此时不需要进行强制转换呢?请问原因是什么? - Lasse V. Karlsen
是的,如果有任何理由需要向读者明确 proxy 扩展了 IDisposable。 - user1228
只要他的代理不是WCF代理,那么使用using块就是安全的。但这是另一个话题。 - Pierre-Alain Vigeant
1
尽管我喜欢使用语句的适当扩展,但我认为说强制转换是不必要的并不在所有情况下都是100%正确的。 - Randy Levy
@LasseV.Karlsen:程序员不一定需要知道对象实现了 IDisposable 接口,而是要知道它 可能 实现了该接口,在需要时必须进行处理。请注意,如果工厂返回的类型可能需要处理但未实现或继承 IDisposable 接口,则应将其视为极端反模式,但如果代码必须与此类工厂一起使用,则 using(foo as IDisposable) 可能是最佳模式。 - supercat

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接