即使没有空检查,使用“as”而不是cast是否有意义?
在开发博客,在线代码示例和(最近)甚至是一本书中,我一直在这样的代码上磕磕绊绊:
var y = x as T; y.SomeMethod();
或者更糟的是:
(x as T).SomeMethod();
这对我来说没有意义。 如果你确定x
是T
types,你应该使用直接转换: (T)x
。 如果你不确定,你可以使用as
但是在执行一些操作之前需要检查null
。 上述代码所做的就是将一个(有用的) InvalidCastException
变成一个(无用的) NullReferenceException
。
我是唯一一个认为这是对as
关键字的公然滥用吗? 还是我错过了明显的东西,上面的模式实际上是有道理的?
你的理解是真实的。 这听起来像试图微观优化我。 当你确定这个types的时候,你应该使用普通的types。 除了产生一个更明智的例外,它也快速失败。 如果你对这个types的假设错了,你的程序将立即失败,你将能够立即看到失败的原因,而不是等待NullReferenceException
或ArgumentNullException
或者将来某个时候会出现逻辑错误。 一般来说,一个as
expression式在某个地方不是一个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”不适用于用户定义的转换,而演员将在适当的时候使用它们。 在某些情况下,这可能是一个重要的区别。
我在这里写了一些关于这个:
我明白你的观点 我同意它的主旨:一个演员操作员沟通“我确信这个对象可以转换成这种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时,会模糊真正的问题。
我一般不会用太多。 我更喜欢is
testing,因为对我来说,它看起来更可读,更有意义,然后尝试一个强制转换和检查为空。
这必须是我最崇拜的人之一 。
Stroustrup的D&E和/或一些我现在找不到的博客文章讨论了一个to
运算符的概念,它将解决https://stackoverflow.com/users/73070/johannes-rossel (即语法与与DirectCast
语义)。
这没有得到实施的原因是因为演员应该导致痛苦和丑陋,所以你被推开使用它。
可惜的是,聪明的程序员(通常是书籍作者(Juval Lowy IIRC))通过滥用这种方式(C ++不提供,可能是出于这个原因)。
即使VB有一个统一的语法,强制你select一个TryCast
或DirectCast
并下定决心更一致!
我相信, 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 }