C#"as"演员与经典演员

Chr*_*ris 132 c# casting

可能重复:
使用CLR中的'as'关键字进行转换

我最近了解了一种不同的演员方式.而不是使用

SomeClass someObject = (SomeClass) obj;
Run Code Online (Sandbox Code Playgroud)

可以使用以下语法:

SomeClass someObject = obj as SomeClass;
Run Code Online (Sandbox Code Playgroud)

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

我看到如果转换失败并且我尝试访问someObject变量,这可能导致NullReferenceException.所以我想知道这种方法背后的理由是什么?为什么要使用这种方式而不是(旧)方式 - 它似乎只是将失败的演员问题"更深"地转移到代码中.

Bri*_*all 160

使用"经典"方法,如果转换失败,则抛出异常.使用as方法,它会导致null,可以检查它,并避免抛出异常.

此外,您只能对引用类型使用"as",因此如果要对值类型进行类型转换,则仍必须使用"经典"方法.

注意:

as方法只能用于可以赋值的类型null.这种用法仅表示引用类型,但是当.NET 2.0出现时,它引入了可空值类型的概念.由于可以为这些类型分配null值,因此它们可以与as运算符一起使用.

  • 此外,"经典"演员阵容可以进行转换.`as`只能做参考/拳击转换. (10认同)
  • `Nullable <T>`是一个值类型(如果用反射器看它,则声明为struct).对于可空类型,运行时必须有一个特殊规则,因为如果我尝试使用"as"转换为int,则确切的编译器错误是"as运算符必须与引用类型或可空类型('int'一起使用)是一个不可为空的值类型)" (5认同)
  • 确切地说,你可以使用"as"和`Nullable <T>`类型(可以为nullable类型是值类型......) (4认同)
  • @Brian,@ Paul:没有运行时"黑魔法".C#和VB.NET语言内置了特定的逻辑来处理`Nullable <T>`.与`null`的比较被转换为`.HasValue`,并且对null的赋值被转换为`= new Nullable <int>()`(或者任何类型是合适的,显然). (3认同)
  • @Brian:正如我所说,没有*运行时*"黑魔法".肯定有很多魔法,但它完全是编译时和语言特有的.运行时不会将`Nullable <T>`视为处理任何其他值类型. (3认同)

Mat*_*ský 31

空比较MUCH比抛出和捕获异常快.例外有很大的开销 - 堆栈跟踪必须组装等.

例外应该代表一种意外状态,这通常不代表情况(哪种情况as更好).

  • 我认为`FileNotFoundException`是一个意想不到的状态.您尝试使用文件执行某些操作而不检查它是否存在,或者您DID确定该文件应该存在且它意外地不存在.没有?:) (22认同)
  • 通常的“过早优化”论点适用于:(a) 性能敏感代码是代码库的一小部分,(b) 在所有其他代码中,优雅(在更自然的应用领域语义建模方面)、可读性和开放性测试是更重要的设计目标,因为我们在这里节省了昂贵的开发人员时间,而不是组装堆栈跟踪所需的纳秒等。 (2认同)

Zoo*_*oba 27

在某些情况下,很容易处理null一个例外.特别是,合并运算符非常方便:

SomeClass someObject = (obj as SomeClass) ?? new SomeClass();
Run Code Online (Sandbox Code Playgroud)

它还简化了您所在的代码(不使用多态性,并根据对象的类型进行分支):

ClassA a;
ClassB b;
if ((a = obj as ClassA) != null)
{
    // use a
}
else if ((b = obj as ClassB) != null)
{
    // use b
}
Run Code Online (Sandbox Code Playgroud)

MSDN页面上所指定,as运算符等效于:

expression is type ? (type)expression : (type)null
Run Code Online (Sandbox Code Playgroud)

这避免了完全支持更快类型测试的异常,但也限制了它对支持null类型(引用类型和Nullable<T>)的使用.

  • if ((a = obj as ClassA) != null) 可以写成 if (obj is ClassA a) 哪个更短更好 (2认同)

Jar*_*Par 7

as在几种情况下,操作员很有用.

  1. 当您只需要知道某个对象属于特定类型但不需要专门对该类型的成员执行操作时
  2. 当你想避免异常而是明确处理时 null
  3. 您想知道对象之间是否存在CLR转换,而不仅仅是某些用户定义的转换.

第三点是微妙但重要的.在使用强制转换运算符的转换和使用运算符成功的转换之间没有1-1映射as.该as操作是严格限制在CLR转换并不会考虑用户定义的转换(转换算符会).

具体而言,as操作员仅允许以下内容(来自C#lang规范的第7.9.11节)

  • 从E的类型存在标识(第6.1.1节),隐式引用(第6.1.6节),装箱(第6.1.7节),显式引用(第6.2.4节)或拆箱(第6.2.5节)转换对T.
  • E或T的类型是开放型.
  • E是空文字.