Effective C# Item3:操作符as或is优于强制转换

    C#是一种强类型的变成语言,我们一般情况下,不推荐大家对变量的类型进行转换,但是针对代码底层来说,为了对业务代码提供尽可能多的支持,很多时候对方法参数的类型不会做强行限制,而只是将其置为System.Object,那么业务在调用这些方法时,如果希望在方法体内执行用户自定义的方法,就必须对参数的类型进行转换,将System.Object转换为用户自己定义的类型。

    关于类型转换,C#有以下两种方式:1.as或者is;2.强制类型转换。我们推荐使用as或者is。

    as进行类型转换时的机制:它会检查对象的运行时类型,是否是期待类型或者期待类型的派生类型,如果是,就进行转换;如果不是,就返回null。对于null来说,它通过as转换为任何类型后,依然是null,并不会产生异常。as并不会执行用户自定义的类型转换。

    强制类型转换的机制:它使用转换操作符来进行类型转换的工作,在这其中,它会执行.NET框架自带的类型转换机制或者用户自定义的类型转换。这其中,就会有转换成功,但是转换后结果不正确的情况,例如将float强行转换成int,就可能会丢失一些信息。在使用时,需要格外注意这一点。

    下面我们看一段非常有趣的代码,来自《Effective C#》一书。

代码
1 public class SecondType
2 {
3 private MyType _value;
4
5 // other details elided
6
7 // Conversion operator.
8 // This converts a SecondType to
9 // a MyType, see item 29.
10   public static implicit operator
11 MyType( SecondType t )
12 {
13 return t._value;
14 }
15 }
16
17 object o = Factory.GetObject( );
18
19 // o is a SecondType:
20 MyType t = o as MyType; // Fails. o is not MyType
21
22 if ( t != null )
23 {
24 // work with t, it's a MyType.
25 } else
26 {
27 // report the failure.
28 }
29
30 // Version two:
31 try {
32 MyType t1;
33 t = ( MyType ) o; // Fails. o is not MyType
34 if ( t1 != null )
35 {
36 // work with t1, it's a MyType.
37 } else
38 {
39 // Report a null reference failure.
40 }
41 } catch
42 {
43 // report the conversion failure.
44 }
     上述代码中,用户自定义了如何将SecondType转换成MyType,然后通过工厂方法返回一个类型为System.Object的对象,其运行时类型是SecondType,接下来使用as和强制转换两种方式将Object转换成MyType。

    上述两种转换都会是失败的,原因:as和强制转换都是针对变量的运行时类型进行处理的,但是上述代码编译时,是去查看变量的编译时类型,编译器是无法得知变量的运行时类型的,因此,虽然上述代码中使用了强制类型转换,会去查看是否有用户自定义的类型转换,但是编译器只会去查看System.Object和MyObject这两种类型之间是否有用户自定义的类型转换,而不会去查看SecondType和MyType之间是否有用户自定义的类型转换。编译器在编译过程中,能够得到和处理的,始终是变量的编译时类型,同时,用户自定义的类型转换,只作用于对象的编译时类型,而不会作用于对象的运行时类型

    如果希望上述代码转换成功,可以写成以下的方式。

代码
1 object o = Factory.GetObject( );
2
3 // Version three:
4 SecondType st = o as SecondType;
5 try {
6 MyType t;
7 t = ( MyType ) st;
8 if ( t != null )
9 {
10 // work with T, it's a MyType.
11 } else
12 {
13 // Report a null reference failure.
14 }
15 } catch
16 {
17 // report the failure.
18 }

 

    以下情况中,是不适合使用as的:

  1. 针对值类型进行类型转换,原因:值类型中不包含null。对于值类型,我们可以先使用is进行类型检查,然后再使用强制类型转换。
  2. foreach语句中的类型转换是强制类型转换,原因:foreach语句的循环变量可能是值类型,也可能是引用类型,因此只能使用强制类型转换。这个也是foreach语句会跑出BadCastException异常的原因。
  3. as进行转换时,会对变量的类型进行检查,当发现变量类型是目标类型或者目标类型的派生类型时,就会进行转换,但是如果我们希望知道变量在运行时详细的类型信息,或者只针对变量是某一特定类型时,才会采取某种操作,这时使用as是不合适的,我们可以使用GetType方法来获取对象的运行时类型的详细信息。  
posted @ 2010-01-03 12:30  李潘  阅读(759)  评论(0编辑  收藏  举报