在C#中使用'as'关键字使转换失败时,返回null。背景中发生了什么?它只是简单地抑制异常,所以我不必为失败编写处理代码吗?
与使用try-catch包装的典型演员相比,我对它的性能特征感兴趣。
答案 0 :(得分:49)
它使用IL指令isinst
来执行强制转换,而不是在转换时使用的castclass
指令。这是一个特殊的指令,如果有效则执行转换,否则在堆栈上留下null
。所以不,它不只是抑制异常,并且比这样做快几个数量级。
请注意,isinst
指令与castclass
之间的行为存在一些差异 - 主要问题是isinst
没有考虑用户定义的强制转换运算符,它只考虑直接继承层次结构,例如如果您定义以下两个没有继承层次结构但是显式强制转换运算符的类:
class A
{
public int Foo;
}
class B
{
public int Foo;
public static explicit operator B(A a)
{
return new B { Foo = a.Foo };
}
}
然后以下内容将成功:
var a = new A { Foo = 3 };
var b = (B)a;
Console.WriteLine(b.Foo); // prints 3
但是以下内容无法编译,错误“无法通过引用转换,装箱转换,拆箱转换,换行转换或空类型转换将类型'A'转换为'B'”
var a = new A { Foo = 3 };
var b = a as B;
因此,如果您确实设置了任何用户定义的强制转换(由于这个原因和其他原因,对引用类型通常是一个坏主意),那么您应该意识到这种差异。
答案 1 :(得分:7)
并加入格雷格的优秀帖子......
第一次在运行时引用新的Type时,CLR将一个名为COREINFO_CLASS_STRUCT
(或类似的东西)的结构加载到内存中,该结构包含指向COREINFO_CLASS_STRUCT
对象的指针。此对象派生自的基类...这有效地为Type的继承链创建COREINFO_CLASS_STRUCT
个对象的链接列表,该列表终止于COREINFO_CLASS_STRUCT
System.Object
。当你执行isinst
,(或它的类似方法castclass
)时,它只需找到你正在检查的对象的具体类型的COREINFO_CLASS_STRUCT
内存结构,并遍历此链表到查看您尝试转换的类型是否在列表中。
它还包含一个指向单独数组的指针,该数组包含Type实现的所有接口,如果您尝试强制转换为接口,则必须单独搜索。