即使没有空检查,使用“as”而不是cast是否有意义?

在开发博客,在线代码示例和(最近)甚至是一本书中,我一直在这样的代码上磕磕绊绊:

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

或者更糟的是:

 (x as T).SomeMethod(); 

这对我来说没有意义。 如果你确定xTtypes,你应该使用直接转换: (T)x 。 如果你不确定,你可以使用as但是在执行一些操作之前需要检查null 。 上述代码所做的就是将一个(有用的) InvalidCastException变成一个(无用的) NullReferenceException

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

你的理解是真实的。 这听起来像试图微观优化我。 当你确定这个types的时候,你应该使用普通的types。 除了产生一个更明智的例外,它也快速失败。 如果你对这个types的假设错了,你的程序将立即失败,你将能够立即看到失败的原因,而不是等待NullReferenceExceptionArgumentNullException或者将来某个时候会出现逻辑错误。 一般来说,一个asexpression式在某个地方不是一个null检查,而是一种代码异味。

另一方面,如果您对演员阵容不确定,并期望演员阵容失败,则应使用包含try-catch块的普通演员阵容。 此外,build议在types检查之后使用as 。 代替:

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

它为is关键字生成isinst指令 ,并为castclass生成isinst指令 (有效地执行两次),您应该使用:

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

这只会生成一个isinst指令。 前一种方法在multithreading应用程序中有一个潜在的缺陷,因为竞争条件可能会导致variables在检查成功并在铸造线失败后改变其types。 后一种方法不容易出现这个错误。


build议不要在生产代码中使用以下解决scheme。 如果你真的讨厌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() 

恕我直言,只要有意义的时候结合一个null检查:

 var y = x as T; if (y != null) y.SomeMethod(); 

使用“as”不适用于用户定义的转换,而演员将在适当的时候使用它们。 在某些情况下,这可能是一个重要的区别。

我在这里写了一些关于这个:

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

我明白你的观点 我同意它的主旨:一个演员操作员沟通“我确信这个对象可以转换成这种types,如果我错了,我愿意冒险例外”,而“as”操作符“我不确定这个对象可以转换为这种types,如果我错了,给我一个null”。

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

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

这篇文章中最明显的一个误导方面是graphics,它并不表示什么是被测量的:我怀疑它是测量失败的转换(其中“as”明显快得多,因为没有例外)。

如果你花时间做这些测量,那么你会发现,如你所期望的那样,当演员成功的时候,演员的速度会比“当” 更快

我怀疑这可能是“货真理”使用as关键字而不是cast的原因之一。

直接投射比as关键字多一个括号。 所以即使在100%确定types的情况下,也能减less视觉混乱。

虽然就exception事情达成协议。 但至less对我来说,大部分的用法都归结为检查null之后,我发现比捕获exception更好。

当我使用“as”时,99%的时间是当我不确定什么是实际的对象types时

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

我不想捕捉明确的投射exception,也不想投两次,使用“是”:

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

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

让我们面对它:类似C语言的转换/转换运算符是非常可怕的,可读性。 如果C#采用了以下的Javascript语法,我希望它更好:

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

或者定义一个to操作符,该等效的操作as

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

人们喜欢这么多,因为它使他们感到安全,从例外…就像保证一盒。 一个人在箱子上保证了一个奇特的保证,因为他希望你能感受到里面的温暖和温暖。 你觉得你晚上把那个小盒子放在你的枕头下,保证仙子可能会下来,离开四分之一,我是对的泰德?

回到主题…使用直接投射时, 可能会出现无效投射exception。 所以,人们将所有的投射需求作为一揽子解决scheme来应用as因为(本身)永远不会抛出exception。 但有趣的是,在你给的例子(x as T).SomeMethod(); 对于空引用exception,您正在交易无效的转换exception。 当你看到exception时,会模糊真正的问题。

我一般不会用太多。 我更喜欢istesting,因为对我来说,它看起来更可读,更有意义,然后尝试一个强制转换和检查为空。

这必须是我最崇拜的人之一 。

Stroustrup的D&E和/或一些我现在找不到的博客文章讨论了一个to运算符的概念,它将解决https://stackoverflow.com/users/73070/johannes-rossel (即语法与与DirectCast语义)。

这没有得到实施的原因是因为演员应该导致痛苦和丑陋,所以你被推开使用它。

可惜的是,聪明的程序员(通常是书籍作者(Juval Lowy IIRC))通过滥用这种方式(C ++不提供,可能是出于这个原因)。

即使VB有一个统一的语法,强制你select一个TryCastDirectCast下定决心更一致!

我相信, as关键字可以被认为是从C ++的dynamic_cast更优雅的外观版本。

没有技术上的原因,它可能更受欢迎,只是因为它更易于阅读,更直观。 (不是说它只是试图回答这个问题而已)

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