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

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

或者,更糟糕的是:

(x as T).SomeMethod();

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

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


当前回答

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

其他回答

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

人们如此喜欢as,因为它让他们觉得没有例外……就像盒子上的担保。一个男人在盒子上放了一个华丽的保证,因为他想让你觉得里面温暖舒适。你觉得晚上把那个小盒子放在枕头下面,担保仙女可能会下来留下25美分,对吗,泰德?

回到正题…使用直接强制转换时,可能会出现无效的强制转换异常。因此,人们将as作为一个全面的解决方案应用于他们所有的强制转换需求,因为as(本身)永远不会抛出异常。但有趣的是,在你给出的例子中(x作为T).SomeMethod();您正在用无效的强制转换异常换取空引用异常。当您看到异常时,会混淆真正的问题。

我一般不会用太多。我更喜欢is测试,因为对我来说,它看起来更可读,比尝试强制转换和检查null更有意义。

使用“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
}

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关键字可以看作是样式更优雅的版本 dynamic_cast来自c++。