2008年11月16日星期日

CLR via C#学习笔记(6)--强制类型转换

CLR中很重要的特性之一就是类型安全性,也就是说,在运行的时候,CLR总是知道一个对象的类型。如果想知道一个对象的确切类型,可以去调用GetType方法,由于这个方法是非虚方法,不可被重写,所以一个类型不能伪装成另一种类型。

开发人员经常需要将一个对象从一种类型转换成其它类型。CLR允许将一个对象强制转换成它的类型或者是它的任何基类型。CLR中的每种编程语言都规定了具体如何将转型操作揭示给开发人员。比如说,C#不需要任何特殊的语法就可以将一个对象转换成任何它的基类型,而C#要求开发人员将对象转换成它的任何派生类型这个操作必须是显式的,因为这种类型有可能在运行时失败。

internal class Employee
{...}

public sealed class Program
{
public static void Main()
{
//不需要转型,因为new返回一个Employee对象,而Employee是Object的派生类型
Object o=new Employee();
//需要转型,因为Employee从Object派生
Employee e=(Employee)o;
//下面的操作可以通过编译,但是在运行时会抛出InvalidCastException异常
//因为dt既不是Employee类型,也不是Employee的派生类型
DateTime dt=DateTime.Now;
Employee e1=(Employee)dt;
}
}

在C#语言中进行强制类型转换的另外一种比较"温和"的方式是使用is操作符,is操作符检查一个对象是否兼容于指定的类型,并返回一个Boolean值。之所以说它比较"温和",是因为is操作符不会抛出异常。is操作符经常这么使用:

if(o is Employee)
{
Employee e=(Employee)o;
}

不过上面的代码CLR实际上检查了两次对象的类型,is操作符首先检测o是否兼容于Employee类型,如果是肯定的,那么在if语句内部执行强制转型时,CLR会再次核实o是否引用一个Employee,CLR的类型检查增强了安全性,但无疑也会对性能造成一定的影响。也因为CLR首先需要判断o引用的对象的实际类型,然后,CLR会遍历继承层次结构,用每个基类型去核对指定的类型(Employee)。由于这种编程模式很常见,所以C#提供了as操作符,目的就是简化这种模式的代码写法,同时提升性能。

Employee e=o as Employee;
if(e!=null)
{
//Using e
}

as与is一样,它不会抛出一个异常——只要对象不能成功转型,它的结果就是null。当然如果不加判断直接使用最终生成的引用的话,可能会造成一个System.NullReferenceException异常。