C# 使用默认转型方法

本文是《编写高质量代码改善C#程序的157个建议》第一章基本语言要素之建议2使用默认转型方法,喜欢本书请到各大商城购买原书,支持正版。

除了字符串操作外,程序员普遍会遇到的第二个问题是:如何正确地对类型实现转型。在上一个建议中,从int转型为string,我们使用了类型int的ToString方法。在大部分情况下,当需要对FCL提供的类型进行转型时,都应该使用FCL提供的转型方法。.

这些转型方法包括:

  • 使用类型的转换运算符。
  • 使用类型内置的Parse、TryParse,或者如ToString、ToDouble、和ToDateTime等方法。
  • 使用帮助类提供的方法。
  • 使用CLR支持的转型。

下面分别对这些方法进行说明。

1.使用类型的转换运行符

使用类型的转换运算符,其实就是使用类型内部的一个方法(即函数)。转换运算符分为两类:隐藏转换和显式转换(强制转换)。基元类型普遍都提供了转换运算符,如:

int i = 0;
float j = 0;
j = i;        // int到float(Single)存在一个隐式转换
i = (int)j;   // float(Single)到int存在,而且必须存在一个显式转换
注意所谓“基元类型”,是指编译器直接支持的数据类型,即直接映射到FCL中的类型。基元类型包括sbyte、byte、short、ushort、int、uint、long、ulong、char、float、double、bool、decimal、object、string。

用户自定义的类型也可以通过重载转换运算符的方式来提供这一类转换,代码如下:

class Program
{
    static void Main(string[] args)
    {
        IP ip = "192.168.0.1";
        Console.WriteLine(ip.ToString());
    }
}

class IP
{
    IPAddress value;

    public IP(string ip)
    {
        value = IPAddress.Parse(ip);
    }

    public static implicit operator IP(string ip)
    {
        IP iptemp = new IP(ip);
        return iptemp;
    }

    public override string ToString()
    {
        return value.ToString();
    }
}

在上面的代码中IP ip = "192.168.0.1";提供的就是字符串到IP之间的隐式转换。但是,除非考虑一些初始值,一般不建议用户对自己的类型重载转换运算符。如果用户自定义的类型之间需要转换,建议从面向对象的角度考虑,因为它们一般都含有某种关系(如继承、实现等)。在这种情况下,就应该使用即将介绍的第四种方法:CLR支持的转型。不过,我们仍需掌握FCL中的类型,尤其是基元类型之间的转换运算符,以便快速地在基元类型间进行转换。

2.使用类型内置的Parse、TryParse,或者如ToString、ToDouble、ToDateTime等方法

在FCL中,如果某个类型经常需要进行转型操作,类型自身则会带有一些转型方法。比如从string转型为int,因为其经常发生,所以int本身就提供了Parse和TryParse方法。一般情况下,如果要对某类型进行类型转换,建议先查阅该类型的API文档。

3.使用帮助类提供的方法

可以使用如System.Convert类、System.BitConverter类来进行类型的转换。

System.Covnert提供了将一个基元类型转换为其他类型的方法,如ToChar、ToBoolean方法等。值得注意的是,System.Convert还支持将任何自定义类型转换为任何基元类型,只要自定义类型继承了IConvertible接口就可以。如上方中的IP类,如果将IP转型为string,除了重写Object的ToString方法外,还可以实现IConvertible的ToString方法,代码如下所示:

class IP:IConvertible
{
    // 省略
    public bool ToBoolean(IFormatProvider provider)
    {
        throw new InvalidCastException("IP-to-Boolean conversion is not supported.");
    }

    public override string ToString()
    {
        return value.ToString();
    }
    // 省略
}

继承IConvertible接口必须同时实现其他转型方法,如上方中的ToBoolean,如果不支持此类转型,则应该抛出一个InvalidCastException,而不是一个NotImplementedException。

System.BitConverter提供了基元类型与字节数组之间相互转换的方法,这里不再赘述。

4.使用CLR支持的转型

CLR支持的转型,即上溯转型和下溯转型。这个概念首先是在Java中提出来的,实际上就是基类和子类之间的相互转换,如图所示:

C# 使用默认转型方法
类的继承

在进行子类向基类转型的时候支持隐式转换,如Dog显然就是一个Animal;而当Animal转型为Dog的时候,必须是显式转换,因为Animal还可能是一个Cat,代码如下所示:

Animal animal;
Dog dog = new Dog();
animal = dog;        // 隐藏转换,因为Dog就是Animal
// dog = animal;     // 编译不通过
dog = (Dog)animal;   // 必须存在一个显式转换