转换类型:(NewType) vs. Object as NewType

92

这两种强制类型转换之间实际上有什么区别呢?

SomeClass sc = (SomeClass)SomeObject;
SomeClass sc2 = SomeObject as SomeClass;

通常情况下,它们都应该是对指定类型的显式转换,是吗?


1
请参见https://dev59.com/rnRB5IYBdhLWcg3w1Kle。这个是最早的,但那个有一个好答案。 - Jay Bazuzi
1
你发布了第二古老的重复问题(第一个已被锁定)!恭喜,我猜? - gparyani
这很有趣,因为这个是3个月前发布的 :) 但另一个帖子有更详细的答案。 - Michael Stum
12个回答

88

如果源类型无法转换为目标类型,前者会抛出异常。后者将导致sc2成为一个空引用,但不会抛出异常。

[编辑]

我的原始答案当然是最显着的区别,但正如Eric Lippert 指出的那样,这并不是唯一的区别。其他差异包括:

  • 您无法使用'as'运算符将其转换为不接受'null'作为值的类型
  • 您无法使用'as'将东西转换为不同表示(例如,将浮点数转换为整数)。

最后,使用'as'与强制转换运算符相比,还表示“我不确定是否成功。”


27

请注意,您只能在引用类型或可空类型中使用关键字“as”。

例如:

double d = 5.34;
int i = d as int;

无法编译

double d = 5.34;
int i = (int)d;

将会编译。


2
由于强制类型转换并不能转换数据类型。 - CiNN

11

使用 "as" 进行类型转换,当转换失败时显然要快得多,因为它避免了抛出异常的开销。

但是,当转换成功时,并不更快。在 http://www.codeproject.com/KB/cs/csharpcasts.aspx 的图表可能会误导人,因为它没有解释其测量内容。

总之:

  • 如果您预计类型转换将成功(即失败将是异常情况),请使用转换操作符。

  • 如果您不知道它是否会成功,请使用 "as" 操作符并测试结果是否为 null。


6

好的,'as'操作符在处理不兼容实例时会返回null,这样您就可以将问题隐藏得更深。也许您会将其传递给一个方法,然后再传递给另一个方法,最终您会遇到NullReferenceException异常,这会使调试变得更加困难。

不要滥用它。在99%的情况下,直接转换操作符更好。


1
这里有非常实用的建议。读者们,请认真考虑。 - mbadawi23
请测试您的对象以针对多种类型。或者,当类型不是预期类型时,您有一个条件并希望执行其他操作。您不会盲目地传递它。您会检查它是否为空,并将逻辑分流或抛出异常。这就是它的作用。您不能滥用好东西。 - T.S.

5
两种方法的区别在于第一种 ((SomeClass)obj) 可能会调用 类型转换器

4
以下是我在决定哪种技术更适合我的情况时所使用的每种技术所遵循的过程的好方法。
DateTime i = (DateTime)value;
// is like doing
DateTime i = value is DateTime ? value as DateTime : throw new Exception(...);

接下来的内容应该很容易猜到它的作用。

DateTime i = value as DateTime;

在第一种情况下,如果无法转换该值,则会抛出异常;在第二种情况下,如果无法转换该值,则将i设置为null。
因此,在第一种情况下,如果转换失败,会发生硬停止,在第二种情况下,会发生软停止,并且您可能会在以后遇到NullReferenceException。

3
所有这些都适用于引用类型,值类型不能使用 as 关键字,因为它们不能为 null。
//if I know that SomeObject is an instance of SomeClass
SomeClass sc = (SomeClass) someObject;


//if SomeObject *might* be SomeClass
SomeClass sc2 = someObject as SomeClass;

使用强制类型转换语法更快,但只有在成功时才快,失败时速度会慢得多。

最佳实践是在不知道类型的情况下使用as

//we need to know what someObject is
SomeClass sc;
SomeOtherClass soc;

//use as to find the right type
if( ( sc = someObject as SomeClass ) != null ) 
{
    //do something with sc
}
else if ( ( soc = someObject as SomeOtherClass ) != null ) 
{
    //do something with soc
}

然而,如果您绝对确定someObjectSomeClass的实例,则使用强制转换。

在.Net 2或更高版本中,泛型意味着您很少需要具有无类型引用类的实例,因此后者较少使用。


3

为了加深对Rytmis评论的解释,你不能在结构体(值类型)中使用as关键字,因为它们没有空值。


2

对于有VB.NET经验的人来说,(type)与DirectCast相同,“as type”与TryCast相同。


1

如果强制转换失败,括号内的转换会抛出异常。而 "as" 转换在转换失败时返回 null。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接