即使没有空检查,使用“as”而不是强制转换是否有意义?

时间:2010-01-26 13:59:05

标签: c# casting type-conversion

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

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

或更糟糕的是:

(x as T).SomeMethod();

这对我没有意义。如果您确定x的类型为T,则应使用直接广播:(T)x。如果您不确定,可以使用as,但在执行某些操作之前需要检查null。上述代码所做的就是将(有用的)InvalidCastException转换为(无用的)NullReferenceException

我是唯一一个认为这是公然滥用as关键字的人吗?或者我是否错过了一些明显的东西,而上述模式实际上是有意义的?

13 个答案:

答案 0 :(得分:250)

你的理解是真的。这听起来像是试图对我进行微观优化。当您确定类型时,应该使用普通的强制转换。除了产生更明智的例外,它也会快速失败。如果您对类型的假设错了,您的程序将立即失败,您将能够立即看到失败的原因,而不是等待NullReferenceExceptionArgumentNullException甚至逻辑将来的错误。一般情况下,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)

恕我直言,asnull支票结合使用时才有意义:

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

答案 2 :(得分:39)

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

答案 3 :(得分:36)

我在这里写了一些关于此的内容:

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)不同的信息。无论什么(),也许这就是代码作者的意图。

答案 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在统一语法方面也更加一致,迫使您选择asTryCast下定决心

答案 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
}