在开发博客、在线代码示例和(最近)甚至是一本书中,我经常遇到这样的代码:

var y = x as T;
y.SomeMethod();

或者,更糟糕的是:

(x as T).SomeMethod();

这对我来说没有意义。如果你确定x是类型T,你应该使用直接强制转换:(T)x。如果不确定,可以使用as,但在执行某些操作之前需要检查是否为空。上面的代码所做的就是将一个(有用的)InvalidCastException转换为一个(没用的)NullReferenceException。

难道只有我一个人认为这是对as关键字的公然滥用吗?还是我错过了一些明显的东西,而上面的模式实际上是有意义的?


当前回答

这是我最讨厌的事之一。

Stroustrup的D&E和/或一些我现在找不到的博客文章讨论了to操作符的概念,它将解决https://stackoverflow.com/users/73070/johannes-rossel提出的观点(即,与as相同的语法,但使用DirectCast语义)。

这个没有被实现的原因是因为施法应该会造成疼痛和丑陋,所以你会被推远使用它。

遗憾的是,“聪明的”程序员(通常是书籍作者(Juval Lowy IIRC))以这种方式滥用as来绕过这一点(c++没有提供as,可能是出于这个原因)。

甚至VB也有统一的语法,迫使你选择TryCast或DirectCast,并做出决定!

其他回答

我认为as关键字可以看作是样式更优雅的版本 dynamic_cast来自c++。

使用“as”不会应用用户定义的转换,而强制转换将在适当的地方使用它们。在某些情况下,这可能是一个重要的区别。

Your understanding is true. That sounds like trying to micro-optimize to me. You should use a normal cast when you are sure of the type. Besides generating a more sensible exception, it also fails fast. If you're wrong about your assumption about the type, your program will fail immediately and you'll be able to see the cause of failure immediately rather than waiting for a NullReferenceException or ArgumentNullException or even a logical error sometime in the future. In general, an as expression that's not followed by a null check somewhere is a code smell.

另一方面,如果您对强制转换不确定,并期望它失败,则应该使用as,而不是用try-catch块包装的普通强制转换。此外,建议在类型检查和强制转换之后使用as。而不是:

if (x is SomeType)
   ((SomeType)x).SomeMethod();

它为is关键字生成isinst指令,为强制转换生成castclass指令(有效地执行两次强制转换),你应该使用:

var v = x as SomeType;
if (v != null)
    v.SomeMethod();

这只会生成一条isinst指令。前一种方法在多线程应用程序中有一个潜在的缺陷,因为竞态条件可能会导致变量在is检查成功后改变其类型,并在转换行处失败。后一种方法不容易出现这种错误。


不建议在生产代码中使用以下解决方案。如果你真的讨厌c#中的这种基本构造,你可以考虑切换到VB或其他语言。

如果一个人非常讨厌强制转换语法,他/她可以写一个扩展方法来模仿强制转换:

public static T To<T>(this object o) { // Name it as you like: As, Cast, To, ...
    return (T)o;
}

使用整齐的[?语法:

obj.To<SomeType>().SomeMethod()

99%的情况下,当我使用“as”时,我不确定实际的对象类型是什么

var x = obj as T;
if(x != null){
 //x was type T!
}

我不想捕捉显式的强制转换异常,也不想使用"is"进行两次强制转换:

//I don't like this
if(obj is T){
  var x = (T)obj; 
}

我在这里写了一点:

http://blogs.msdn.com/ericlippert/archive/2009/10/08/what-s-the-difference-between-as-and-cast-operators.aspx

我明白你的意思。我同意它的重点:强制转换操作符传达的是“我确信这个对象可以转换为那种类型,如果我错了,我愿意冒一个异常的风险”,而“as”操作符传达的是“我不确定这个对象可以转换为那种类型;如果我错了,就给我一个null。”

然而,有一个微妙的区别。whatever()表示“我知道x不仅可以转换为T,而且这样做只涉及引用或开箱转换,而且x不是空的”。这确实传达了不同于(T)x). whatever()的信息,也许这就是代码作者的意图。