在开发博客,在线代码示例和(最近)甚至是一本书中,我一直在寻找像这样的代码:
var y = x as T; y.SomeMethod();
或者更糟糕的是:
(x as T).SomeMethod();
这对我来说没有意义.如果你确定它x
是类型T
,你应该使用直接演员:(T)x
.如果您不确定,可以使用as
但需要null
在执行某些操作之前进行检查.以上代码所做的就是将(有用)InvalidCastException
变为(无用)NullReferenceException
.
我是唯一一个认为这是公然滥用as
关键字的人吗?还是我错过了一些明显的东西,上面的模式实际上有意义?
你的理解是真的.这听起来像是试图对我进行微观优化.当您确定类型时,应该使用普通的强制转换.除了产生更明智的例外,它也会快速失败.如果你错了你对类型的假设,你的程序将立即失败,你就可以看到失败的原因立即而不是等待NullReferenceException
或者ArgumentNullException
甚至是一个逻辑错误在将来某个时候.通常,在某处as
没有null
检查的表达式是代码气味.
另一方面,如果你不确定演员并且期望它失败,你应该使用as
而不是用try-catch
块包裹的普通演员.此外,as
建议使用类型检查,然后进行强制转换.代替:
if (x is SomeType) ((SomeType)x).SomeMethod();
其产生的isinst
指令为is
关键字,和castclass
指令的投(有效执行转换两次),你应该使用:
var v = x as SomeType; if (v != null) v.SomeMethod();
这只会生成一条isinst
指令.前一种方法在多线程应用程序中存在潜在缺陷,因为竞争条件可能导致变量在is
检查成功后更改其类型并在转换线处失败.后一种方法不容易出现这种错误.
建议不要在生产代码中使用以下解决方案.如果你真的讨厌C#中这样一个基本的构造,你可以考虑切换到VB或其他语言.
如果一个人极度讨厌强制转换语法,他/她可以编写一个扩展方法来模仿强制转换:
public static T To(this object o) { // Name it as you like: As, Cast, To, ... return (T)o; }
并使用整洁的[?]语法:
obj.To().SomeMethod()
恕我直言,as
结合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
我理解你的观点.我同意它的主旨:一个演员操作员传达"我确信这个对象可以转换为那种类型,如果我错了,我愿意冒一个例外",而"as"运算符进行通信"我不确定这个对象是否可以转换为那种类型;如果我错了就给我一个空".
但是,有一个微妙的区别.(x为T).Whatever()传达"我不仅知道x可以转换为T,而且这样做只涉及引用或拆箱转换,而且x不是空".这确实传达了与((T)x)不同的信息.无论什么(),也许这就是代码作者的意图.
我经常看到这篇误导性文章的引用作为"as"比铸造更快的证据.
本文中一个更明显的误导性方面是图形,它没有表明正在测量的内容:我怀疑它正在测量失败的强制转换(其中"as"显然要快得多,因为没有抛出异常).
如果你花时间进行测量,那么你会发现,正如你所期望的那样,铸造比铸造成功时的"as" 更快.
我怀疑这可能是"货物崇拜"使用as关键字而不是演员表的一个原因.
直接投射比as
关键字需要一对括号.因此,即使在您100%确定类型是什么的情况下,它也可以减少视觉混乱.
但是就异常事项达成了一致意见.但至少对我而言,大多数使用as
煮沸null
以后检查,我觉得比捕捉异常更好.
当我使用"as"时,99%的时间是我不确定实际对象类型是什么时候
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; }
这只是因为人们喜欢它的外观,它非常易读.
让我们面对现实:C语言中的转换/转换运算符非常可怕,可读性方面.如果C#采用以下Javascript语法,我希望它更好:
object o = 1; int i = int(o);
或者定义一个to
运算符,相当于as
:
object o = 1; int i = o to int;
人们喜欢as
这么多,因为它让他们感到安全,不受例外的影响...就像盒子上的保证一样.一个人在盒子上放了一个奇特的保证,因为他希望你感觉内心温暖和温暖.你认为你晚上把那个小盒子放在你的枕头下,保证仙女可能会下来并离开四分之一,我是不是特德?
回到主题...当使用直接强制转换时,可能存在无效的强制转换异常.所以人们将其as
作为一个全面的解决方案应用于他们所有的铸造需求,因为as
(本身)永远不会抛出异常.但有趣的是,在你给(x as T).SomeMethod();
你的示例中,为空引用异常交易了一个无效的强制转换异常.当您看到异常时,会混淆真正的问题.
我一般不会用as
太多.我更喜欢is
测试,因为对我来说,它看起来更具可读性,然后尝试演员和检查null更有意义.
这必须是我最大的烦恼之一.
Stroustrup的d&E和/或一些博客文章中,我找不到,现在讨论一个概念to
操作这就解决所作出的点/sf/ask/17360801/(即,相同的语法,as
但是DirectCast
语义).
这没有得到实施的原因是因为演员阵容应该引起痛苦并且丑陋,所以你不能使用它.
遗憾的是,"聪明"的程序员(通常是书籍作者(Juval Lowy IIRC))as
以这种方式滥用(C++不提供as
,可能是出于这个原因).
即使VB在具有一致的语法,迫使你选择一个更具一致性TryCast
或DirectCast
和让你的心!