如果类型转换无可避免,那么应该尽可能用as运算符,而不是强制转换
C#是一个强数据类型语言。好的编程实践意味着当可以避免从一种数据类型强制转化为另种数据类型时,我们应该尽我们的所能来避免它。但在某些时候,运行时类型检测是不可避免的。在C#里,大多数时候你要为调用函数的参数使用System.Object类型,因为Framwork已经为我们定义了函数的原型。你很可能要试图把那些类型进行向下转化为其它类型的接口或者类。你有两个选择:用as运算符,或者,采用旧式的C风格,强制转换。(不管是哪一种,)你还必须对变量进行保护:你可以试着用is进行转换,然而再用as进行转换或者强制转换。
那么,我们的原则就是:在类型转换无可避免的时候,优先使用as运算符,而不是强制转换。
为什么呢?
as运算符可以提供更加好的类型安全,这得从两个方面讲。第一,as运算符是编译时检查的,如果两个类型无法转换,则编译即无法通过,这样当然就避免了问题的发生。第二,在处理null的时候,as运算符会对Null值返回一个null引用,而不会抛出异常。
object o = Factory.GetObject( );
// Version one:
MyType t = o as MyType;
if ( t != null )
{
// work with t, it's a MyType.
} else
{
// report the failure.
}
或者你这样写:(使用强制转换)
object o = Factory.GetObject( );
// Version two:
try {
MyType t;
t = ( MyType ) o;
if ( t != null )
{
// work with T, it's a MyType.
} else
{
// Report a null reference failure.
}
} catch
{
// report the conversion failure.
}
以上两个代码显然第二个是更加繁琐的,因为强制转换操作符是运行时检查,如果尝试对一个null进行强制转换,则会收到下面的异常。所以我们一般要用try…catch…语句块
另外,与as运算符有联系的还有一个运算符,就是is,它是判断两个类型可以互相转换。如果可以,则返回true,反之(或者null),则返回false.这个运算符也是类型安全的。
那么,问题的关键在于,如果强制转换有这些毛病,为什么还要保留呢?我们一般可以这样来理解
1. 首先,保留强制转换是为了与早先的语言,例如C,c++保持一致性。
2. 其次,强制转换一定会有它特定的用途。
第一点,我们不需要太多解释,语言延续性嘛。关于第二点,我们来看看到底怎么理解?
我们知道类型转换其实是相当复杂的:例如我要把Class1转换为Class2, 而你要知道Class1和Class2是没有关系的,那么如果我们不定义一种联系,.NET执行引擎就自然不可能知道怎么转换。为了做这样的事情,我们一般会在Class1上面定义一个特定的操作符(可以是显式的,也可以是隐式的)。而只要类型有这种所谓的自定义转换,as运算符就不能工作了。此时,必须用到强制转换。请看下面的例子
static void Main(string[] args)
{
Class1 c1 = new Class1();
Class2 c2 = c1;//这是隐式转换,不需要任何的操作符
Class3 c3 = (Class3)c1;//这是显式转换
Console.WriteLine(c2);
Console.WriteLine(c3);
//使用as操作符,无法通过编译
//Console.WriteLine(c1 as Class2);
Console.Read();
}
class Class1
{
public int Value { get; set; }
/// <summary>
/// 这是隐式转换。转换的时候什么附加代码都不要,但是等同于强制转换
/// </summary>
/// <param name="c1"></param>
/// <returns></returns>
public static implicit operator Class2(Class1 c1)
{
return new Class2() { Value = c1.Value };
}
/// <summary>
/// 这是显示转换。转换的时候必须写强制转换符
/// </summary>
/// <param name="c1"></param>
/// <returns></returns>
public static explicit operator Class3(Class1 c1)
{
return new Class3() { Value = c1.Value };
}
}
class Class2
{
public int Value { get; set; }
}
class Class3
{
public int Value { get; set; }
}
最后,不得不提一下,在.NET 2.0中通过泛型技术可以更好地编程,之前我也有介绍过。