8
10
2015
0

[Effective C#] Item 3: Prefer the is or as Operators to Casts


优先使用is或as操作符而不是强制类型转换。

然而我一直用强制类型转换来着……

C#是强类型的,这意味着可以让编译器完成大多数的类型检查。但是,有时候运行时类型检查时不可避免的,例如,因为.NET框架定义了某个方法的原型,有时需要写一个获取object类型的参数的方法。这时就需要进行类型转换。对于这种情况,C#提供了两种方法:as操作符和强制类型转换。

as操作符检查对象的运行时类型是否是目标类型或其派生类,如果是,返回作为目标类型的原类型的引用,否则返回null。注意,as操作符仅仅改变了类型,返回的还是对原来对象的引用,不会构造新的对象。另外,as操作符的右边不能是值类型,所以也不能进行拆箱操作。

而强制类型转换除了和执行as操作符一样的检查以外,还检查对象的编译时类型是否有用户定义的到目标类型的转换。不过,不用担心这两种转换之间的冲突,因为C#不允许在基类和派生类之间另外定义转换。强制类型转换在转换失败时将会抛出一个InvalidCastException。

现在通过代码来比较一下两种转换方式。

首先由如下的定义。

下面分别是两种转换方法的代码。

显然第一份代码更简单易读,而且因为不用进行异常处理,也更高效。

同时,强制类型转换可以调用用户定义的转换,这可能导致很多问题。

首先,用户定义的转换可能构造的新的对象,这可能会导致性能问题以及非预期的行为。

其次,因为对用户定义的转换的检查基于编译时类型,这也会导致非预期行为。可以看下面这个例子。

有这样一些声明。

现在要执行这样一段代码。

这段代码看起来能够工作,但实际上会失败。考虑编译器的做法,首先它发现b在编译时是一个object,于是检查是否存在从object到SampleClassA的用户定义的转换,发现没有,于是编译器将生成IL用于检查b的运行时类型是否是SampleClassA或其派生类。编译器并不知道b的运行时类型是SampleClassB,所以不能生成调用从SampleClassB到SampleClassA的用户定义的转换的IL。(实际上如果使用反射可能可以做到,但是编译器显然没有这么做,也没必要这么做)

最后再来说一下is操作符。其实很简单,is操作符返回的是如果把is换成as,是否会返回null。要注意的是,这意味着如果对一个null引用使用is,返回值总是false。

Category: C#及OOP | Tags: Effective C# | Read Count: 459

登录 *


loading captcha image...
(输入验证码)
or Ctrl+Enter

Host by is-Programmer.com | Power by Chito 1.3.3 beta | Theme: Aeros 2.0 by TheBuckmaker.com