类型与通用语言运行时:类型转换
CLR 最重要的一个特性就是类型安全。CLR 在运行时总能知道一个对象的类型。我们也可以用过调用 GetType方法来得到对象的准确类型。因为该方法是一个虚方法。所以我们不可能利用它来篡改一个类型的信息。
例如:我们不可能重写 Employee 类的 GetType方法使之返回一个SpaceShuttle类型。
作为开发人员,我们经常会遇到需要将一个对象转换为其他类型。 CLR 允许我们将对象转换为其原来的类型或者它的任何一个基类型。各个编程语言自己决定如何提供这些转型操作。
例如,C# 不需要任何特殊的语法就可以将对象转换为其任何一个基类型,因为转换为基类型被认为是安全的隐式操作。然而在其将对象转换为它的任何派生类型时,C# 要求进行显式转换,因为这样的转型有可能会失败
下面的代码将演示如何将对象转化为它的基类和派生类型:
1 //该类型隐式继承自 System.Object 2 class Employee{ 3 ... 4 } 5 6 class App{ 7 public static void Main(){ 8 9 //这里不需要转型,因为 new 返回的是一个 Employee 对象 10 //而 Object 又是 Employee 的基类型 11 Object o = new Object (); 12 13 //这里需要转型,因为 Employee 继承自 Object 14 //其它一些语言可能不需要转型 15 Employee e = ( Employee )o; 16 17 } 18 }
上面的例子显示了要使代码通过编译我们需要做的一些事情,下面解释运行时发生的行为,在运行时CLR会检查转型操作以确保总是将对象转型它的实际类型、或者它的任何基类型。
例如,下面的代码虽然能够通过编译,但是运行时,却会抛出 InvalidCastException 异常:
1 class Manager:Employee { 2 3 ... 4 5 } 6 7 8 class App{ 9 10 public static void Main() { 11 12 //构造一个 Manager 对象并将其传递给 PromoteEmployee 13 14 //一个 Manager " Is-A" Object.PromoteEmployee 将正常运行 15 16 Manager m = new Manager(); 17 18 PromoteEmployee(m); 19 20 21 //构造一个DateTime 对象并将其传递给 PromoteEmployee 22 23 //由于 DateTime 并非继承自 Employee,因此 PromoteEmployee 会抛出一个 System.InvalidCastException 异常 24 25 DateTime newYears = new DateTime(2016,1,1); 26 27 PromoteEmployee(newYears); 28 29 } 30 31 public static void PromoteEmployee(Object o) { 32 33 //这里,编译器并不知道对象 o 引用的实际类型,所以编译器允许代码通过编译 34 35 //当代码运行时,CLR会获知 o 的引用类型(每当进行转型操作时), 36 37 //并且会检查对象的类型是否是Employee,或者是任何继承自Employee的类型 38 39 Employee e = (Employee) o; 40 41 ... 42 43 } 44 45 }
如果 CLR 允许上例中的转型操作,代码则会失去类型安全,并且结果也将变得不可预期——包括应用程序可能崩溃、以及由于类型欺骗引起的安全漏洞。
类型欺骗是很多安全漏洞的原因,它会极大地危机应用程序的 稳定性和健壮性。
* PromoteEmployee()的正确定义应该是接受一个 Employee对象,而不是 Object 对象作为参数,本文使用 Object 的目的仅仅只是为了演示编译器和 CLR 是如何处理转型操作的。
使用 is 和 as 操作符转型(C#)
检查对象是否和给定的类型兼容,并返回判断结果:true 或者 false 。另外,is 操作符永远不会抛出异常。
看下面的代码:
System.Object o = new System.Object ();
System.Boolean b1 = ( o is System.Object); // b1 为true
System.Boolean b1 = ( o is Employee); // b1 为false
如果对象引用为null,那么 is 操作符总是返回 false,因为没有对象可以用来检查其类型。下面演示 is 操作符典型的使用方法:
if( o is Employee){
Employee e = (Employee) o;
//在 "if" 语句中使用 e
}
在上面的代码中,CLR实际上对对象的类型检查了两次:is操作符首先检查 o 所引用的对象是否和 Employee 类型兼容。如果兼容,在 if 语句内,
CLR 在执行转型时又会检查 o 是否为一个 Employee 引用。由于这种编程范式十分常见,C#便为我们提供了一种新的转型方式,即 as 操作符,它可
以在简化代码的同时提高性能,例如:
Employee e = o as Employee;
if(e != null) {
//在 "if" 语句中使用 e
}
在上面的代码中,CLR 会检查 o 所引用的对象是否和 Employee 类型兼容,如果兼容,as 返回一个指向同一个对象的非空指针。如果不兼容,as 返回 null.
注意,在 as 操作符执行过程中,CLR只检查了一次对象的类型。紧接着的 if 语句只需要检查 e 是否为null 就可以

浙公网安备 33010602011771号