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

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

或者,更糟糕的是:

(x as T).SomeMethod();

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

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


当前回答

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

其他回答

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()

它之所以更受欢迎,可能不是因为技术原因,而是因为它更容易阅读,更直观。(不是说这样会更好,只是试着回答问题)

使用“as”的一个原因是:

T t = obj as T;
 //some other thread changes obj to another type...
if (t != null) action(t); //still works

而不是(坏代码):

if (obj is T)
{
     //bang, some other thread changes obj to another type...
     action((T)obj); //InvalidCastException
}

只是因为人们喜欢它的样子,所以它很有可读性。

让我们面对现实吧:类c语言中的强制转换操作符在可读性方面相当糟糕。我希望它更好,如果c#采用Javascript语法:

object o = 1;
int i = int(o);

或者定义一个to操作符,相当于as的强制转换:

object o = 1;
int i = o to int;

我经常看到这篇误导性文章的引用,作为“as”比cast更快的证据。

本文中比较明显的误导之一是图表,它没有指出要度量的是什么:我怀疑它度量的是失败的强制转换(其中“as”显然要快得多,因为没有抛出异常)。

如果您花时间进行测量,那么您将看到,当强制转换成功时,强制转换比“as”更快。

我怀疑这可能是“货物崇拜”使用as关键字而不是演员的原因之一。