使用“is”后跟“as”而不是“as”后跟C#中的空值检查有什么意义?

时间:2011-08-22 11:39:23

标签: c# .net casting

在阅读C#代码时,我发现了一个相当奇怪的片段:

if( whatever is IDisposable) {
  (whatever as IDisposable).Dispose();
}

我宁愿期待这样做:

if( whatever is IDisposable) { //check
  ((IDisposable)whatever).Dispose(); //cast - won't fail
}

或者像这样:

IDisposable whateverDisposable = whatever as IDisposable;
if( whateverDisposable != null ) {
   whateverDisposable.Dispose();
}

我的意思是as就像演员,但失败时会返回null。在第二个片段中,它不会失败(因为之前有is检查)。

在第一个代码段中编写代码而不是在第二个或第三个代码中编写代码有什么意义?

8 个答案:

答案 0 :(得分:15)

你是对的。第一个片段没有意义。

从替代方案中,我建议使用第三种,因为它在检查和方法调用之间的意义上是线程安全的,对象不能被另一个没有实现接口的对象替换。请考虑以下使用第二个代码段的方案:

if (whatever is IDisposable) { //check 
    // <-- here, some other thread changes the value of whatever
    ((IDisposable)whatever).Dispose(); // could fail
} 

第三个片段不会发生这种情况。

注意:演员与as之间在用户定义的转化方面有some subtle differences,但在这种情况下它们不适用。

答案 1 :(得分:3)

as为真之后无法使用is,我怀疑您阅读的代码或本书仅向您展示如何声明和使用as和{ {1}}。我会像你在第二个片段中建议的那样使用它:

is

另请注意,在您第一次尝试“IDisposable whateverDisposable = whatever as IDisposable; if( whateverDisposable != null) { whateverDisposable.Dispose(); } ”时,您正在投射将会占用“施法时间”的对象,此处您使用((IDisposable)whatever)和第二次投射两次使用显式强制转换,所以最好的方法是使用第二种方法“as然后检查它是否as IDisposable”来实现它。

答案 2 :(得分:3)

正如您所怀疑的那样,

is后跟as是一个毫无意义的构造。最终,如果你不确定它是什么类型或它实现了什么接口,有两个成语 - 一个用于引用类型,一个用于值类型。

在测试引用类型(或盒装可空)时,您提供的最后一个模式是正确的 - as后跟空测试。这将是最快的方法,因为运行时只需执行一种类型测试。

在测试盒装值类型时,您提供的第二种模式是正确的 - is后跟投射。

答案 3 :(得分:2)

同意这一点,但如果你真的看起来很干净,那么扩展方法怎么样:

public static void DisposeIfNecessary(this object obj)
{
   if (obj != null && obj is IDisposable)
      ((IDisposable)obj).Dispose();
}

答案 4 :(得分:1)

你是对的,你发布的第一个代码是不必要的。如果您希望铸造变量的范围在if内,请使用第二个,如果无关紧要,则使用第三个,因为它的工作量最少。

答案 5 :(得分:1)

此外,最后一个选项显然为您提供了一个范围内变量,您可以在以后重复使用,而无需重新调用强制转换。

答案 6 :(得分:1)

is后跟as是没有意义的,除了更快地输入(因为括号需要击键以及intellisense与as有多大帮助)。是略慢于其他两个示例,因为运行时需要进行两次类型检查。

CLR对as有一些诡计,因此应该is跟随演员更快(但请记住,你可以' t使用as和值类型。)

答案 7 :(得分:1)

回答你的实际问题:经验和习惯。

在.Net 2.0中包含as关键字之前,安全地确定对象是否可以转换为特定类型/接口的唯一方法是使用is关键字。

因此,人们养成了在尝试显式转换之前使用is的习惯,以避免不必要的异常。这导致您在样本列表中排在第二位的模式:

if(whatever is IDisposable)  //check
{
  ((IDisposable)whatever).Dispose(); //cast - won't fail
}

然后,我们获得了安全投射as关键字。我猜大多数人,当他们第一次开始使用as时,继续使用熟悉的模式,但用安全演员代替直接演员,他们选择的模式演变成你的例子1.(我知道我这样做了一段时间。)

if(whatever is IDisposable) 
{
  (whatever as IDisposable).Dispose();
}

最终,许多人或大多数人自己意识到,或者被fxCop或CodeAnalysis指示“正确”模式是你的榜样3:

IDisposable whateverDisposable = whatever as IDisposable;
if(whateverDisposable != null ) 
{
    whateverDisposable.Dispose();
}

当然还有一些漂浮在示例1阶段的人仍然没有“进化”他们的模式出于某种原因你的模式3,或者其他人仍然只是使用久经考验的古老模式使用is后跟直接演员。