C#“如”投与经典剧组

可能重复:
在CLR中使用“as”关键字进行投射

我最近了解到一个不同的投资方式。 而不是使用

SomeClass someObject = (SomeClass) obj; 

可以使用这个语法:

 SomeClass someObject = obj as SomeClass; 

如果obj不是一个SomeClass,它似乎返回null,而不是抛出一个类转换exception。

我看到,如果转换失败,可能会导致NullReferenceException,并尝试访问someObjectvariables。 所以我想知道这个方法的基本原理是什么? 为什么要使用这种铸造方式而不是(旧的) – 它似乎只是把一个失败的“更深”的问题转移到代码中。

使用“经典”方法,如果转换失败,则抛出exception。 用as方法,结果为null,可以检查,避免抛出exception。

另外,只能使用“as”作为引用types,所以如果要将types转换为值types,则仍然必须使用“classic”方法。

注意:

as方法只能用于可以赋值为null值的types。 这只是意味着引用types,但是当.NET 2.0推出时,它引入了可为空的值types的概念。 由于这些types可以分配一个null值,所以可以和as运算符一起使用。

空比较比投掷和捕捉exception要快得多。 exception有很大的开销 – 堆栈跟踪必须组装等。

exception应该代表一个意想不到的状态,这往往不代表情况(这是什么时候效果更好)。

在某些情况下,很容易处理一个null不是一个exception。 特别是,合并运算符很方便:

 SomeClass someObject = (obj as SomeClass) ?? new SomeClass(); 

它还简化了你所在的代码(不使用多态),并基于对象的types进行分支:

 ClassA a; ClassB b; if ((a = obj as ClassA) != null) { // use a } else if ((b = obj as ClassB) != null) { // use b } 

如在MSDN页面中所指定的asas运算符等同于:

 expression is type ? (type)expression : (type)null 

这避免了完全有利于快速typestesting的exception,而且还将其用于支持nulltypes(引用types和Nullable<T> )。

as运算符在几种情况下很有用。

  1. 当你只需要知道一个对象是一个特定的types,但不需要专门对这个types的成员进行操作
  2. 当你想避免exception,而是明确处理null
  3. 您想知道对象之间是否存在CLR转换,而不仅仅是一些用户定义的转换。

第三点是微妙但重要的。 铸造操作符和用as操作符成功的操作之间不会有1-1映射关系。 as运算符严格限于CLR转换,不会考虑用户定义的转换(演员操作符将会)。

具体来说, as运算符仅允许以下内容(来自C#lang规范的第7.9.11节)

  • 隐式引用(6.1.6),装箱(6.1.7),显式引用(6.2.4)或拆箱(6.2.5)到T.
  • E或T的types是开放types。
  • E是空字面。

当你真的不知道variables可能是什么types时, as关键字是有用的。 如果您有一个函数会根据实际的参数types使用不同的代码path,那么您有两个select:

首先,使用普通的演员:

 if(myObj is string) { string value = (string)myObj; ... do something } else if(myObj is MyClass) { MyClass = (MyClass)myObj; } 

这要求你使用is检查对象的types,这样你就不会试图把它转换成失败的东西。 这也是稍微多余的,因为is type检查是在cast中重新执行的(所以如果需要的话可以抛出exception)。

另一种方法是使用as

 string myString = myObj as string; MyClass myClass = myObj as MyClass; if(myString != null) { } else if(myClass != null) { } 

这使代码稍微短一点,也消除了冗余types检查。

使用as会返回null,如果不是一个有效的转换,它允许除了在try / catch中包装转换之外还可以做其他事情。 我讨厌经典的演员。 如果我不确定,我总是会使用。 另外,例外是昂贵的。 空检查不是。

我认为最好的“规则”是只在预期你的主题不会是你正在投射的对象时才使用“as”关键字:

 var x = GiveMeSomething(); var subject = x as String; if(subject != null) { // do what you want with a string } else { // do what you want with NOT a string } 

然而,当你的主题应该是你所投的types的时候,就像你所说的那样,使用“经典的演员”。 因为如果不是你期望的types,你会得到一个符合特殊情况的例外。

这里没有什么深层的事情发生。基本上,testing某些东西是否属于某种types(例如使用“as”)是很方便的。 你会想检查'as'调用的结果,看看结果是否为空。

当你期望一个强制转换工作,你想抛出exception,使用“经典”的方法。

您可以使用“as”语句来避免发生exception,例如,您可以通过逻辑优雅地处理强制转换失败。 只有在确定对象是所需的types时才使用该强制转换。 我几乎总是使用“作为”,然后检查为空。

我想这是有用的,如果转换的结果将被传递给你知道将处理空引用没有抛出和ArgumentNullException或类似的方法。

我倾向于发现很less使用,因为:

 obj as T 

比:慢

 if (obj is T) ...(T)obj... 

对于我来说,使用as是一个非常边缘的情况,所以我不能想到什么时候使用它的一般规则,只是将更多的(更多的信息)转换exception在堆栈上进行处理和处理。