在开发博客,在线代码示例和(最近)甚至是一本书中,我一直在寻找像这样的代码:
var y = x as T;
y.SomeMethod();
或更糟糕的是:
(x as T).SomeMethod();
这对我没有意义。如果您确定x
的类型为T
,则应使用直接广播:(T)x
。如果您不确定,可以使用as
,但在执行某些操作之前需要检查null
。上述代码所做的就是将(有用的)InvalidCastException
转换为(无用的)NullReferenceException
。
我是唯一一个认为这是公然滥用as
关键字的人吗?或者我是否错过了一些明显的东西,而上述模式实际上是有意义的?
答案 0 :(得分:250)
你的理解是真的。这听起来像是试图对我进行微观优化。当您确定类型时,应该使用普通的强制转换。除了产生更明智的例外,它也会快速失败。如果您对类型的假设错了,您的程序将立即失败,您将能够立即看到失败的原因,而不是等待NullReferenceException
或ArgumentNullException
甚至逻辑将来的错误。一般情况下,as
表达式后面没有null
检查,这是代码气味。
另一方面,如果您不确定演员表并且期望它失败,您应该使用as
而不是使用try-catch
块包裹的普通演员表。此外,建议使用as
进行类型检查,然后进行强制转换。而不是:
if (x is SomeType)
((SomeType)x).SomeMethod();
为is
关键字生成isinst
instruction,为演员生成castclass
instruction(有效执行演员投注两次),您应该使用:
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()
答案 1 :(得分:42)
恕我直言,as
与null
支票结合使用时才有意义:
var y = x as T;
if (y != null)
y.SomeMethod();
答案 2 :(得分:39)
使用'as'不会应用用户定义的转换,而演员将在适当的时候使用它们。在某些情况下,这可能是一个重要的区别。
答案 3 :(得分:36)
我在这里写了一些关于此的内容:
我理解你的观点。我同意它的主旨:一个演员操作员传达“我确信这个对象可以转换为那种类型,如果我错了,我愿意冒一个例外”,而“as”运算符进行通信“我不确定这个对象是否可以转换为那种类型;如果我错了就给我一个空”。
然而,有一个微妙的区别。 (x为T).Whatever()传达“我不仅知道x可以转换为T,而且这样做只涉及引用或拆箱转换,而且x不是空”。这确实传达了与((T)x)不同的信息。无论什么(),也许这就是代码作者的意图。
答案 4 :(得分:16)
我经常看到this misleading article的引用作为“as”比铸造更快的证据。
本文中一个更明显的误导性方面是图形,它没有表明测量的是什么:我怀疑它正在测量失败的演员表(其中“as”显然要快得多,因为没有抛出异常)。
如果您花时间进行测量,那么您会看到,当演员成功时,正如您所期望的那样,更快而不是“as”。
我怀疑这可能是“货物崇拜”使用as关键字而不是演员表的原因之一。
答案 5 :(得分:11)
直播需要比as
关键字多一对括号。因此,即使在你100%确定类型是什么的情况下,它也会减少视觉混乱。
同意异常的事情。但至少对我而言,as
的大部分用法都会在事后检查null
,我发现这比使用异常更好。
答案 6 :(得分:8)
99%的时间我使用“as”是因为我不确定实际的对象类型是什么
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;
}
答案 7 :(得分:8)
这只是因为人们喜欢它的外观,它非常易读。
让我们面对现实:C语言中的转换/转换运算符非常可怕,可读性方面。如果C#采用以下Javascript语法:
,我希望它更好object o = 1;
int i = int(o);
或定义to
运算符,等效于as
:
object o = 1;
int i = o to int;
答案 8 :(得分:5)
人们喜欢as
这么多,因为它让他们感到安全,不受异常的影响...就像盒子上的保证一样。一个人在盒子上放了一个奇特的保证,因为他希望你感觉内心温暖和温暖。你认为你晚上把那个小盒子放在你的枕头下,保证仙女可能会下来并离开四分之一,我是不是特德?
回到主题...当使用直接强制转换时,存在无效强制转换异常的可能性。因此,人们应用as
作为他们所有投射需求的一揽子解决方案,因为as
(本身)永远不会抛出异常。但有趣的是,在您给出(x as T).SomeMethod();
的示例中,您正在为空引用异常交易无效的强制转换异常。当您看到异常时,会混淆真正的问题。
我通常不会过多使用as
。我更喜欢is
测试,因为对我而言,它似乎更具可读性,并且在尝试强制转换和检查null时更有意义。
答案 9 :(得分:5)
这必须是我top peeves之一。
Stroustrup的D&amp; E和/或我现在无法找到的一些博客文章讨论了to
运算符的概念,它将解决https://stackoverflow.com/users/73070/johannes-rossel所提出的观点(即与{{1}相同的语法但是用as
语义)。
这个没有得到实施的原因是因为演员阵容会引起痛苦并且变得难看,所以你会被迫使用它。
可惜,“聪明”的程序员(通常是书籍作者(Juval Lowy IIRC))以这种方式滥用DirectCast
来解决这个问题(C ++并不提供as
,可能是因为这个原因。) / p>
甚至VB在统一语法方面也更加一致,迫使您选择as
或TryCast
和下定决心!
答案 10 :(得分:2)
我相信as
关键字可以被认为是更优雅的版本
来自C ++的dynamic_cast
。
答案 11 :(得分:1)
它可能更受欢迎,没有技术原因,只是因为它更容易阅读和更直观。 (并不是说它只是试图回答这个问题更好)
答案 12 :(得分:1)
使用“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
}