C#类型转换

在C#中,不同类型之间可以进行转换。

隐式转换

不同类型的数字的表达范围是不一样的,容纳表示范围小的的类型可以直接赋值给表达范围大的类型,这就是隐式转换。

整数类型的隐式

static void Main(string[] args){
    int i = 100;
    long j = i;
}

整数的隐式转换是没有数据损失的。

浮点数的隐式转换

static void Main(string[] args){
    int i = 100;
    double j = i;
}

浮点数表示范围比整数大,可以将整数隐式转换成浮点数,但是注意,整数在转换成浮点数时有精度损失。

整数和小数的隐式转换

static void Main(string[] args){
	int i = 100;
    decimal j = i;
}

可以将整数隐式转换成小数,而且没有精度损失。

自定义的隐式转换

可以为类和结构也提供隐式转换。

public class XName
{
    string name;

    public XName(string name){
        this.name = name;
    }

    public static implicit operator XName(string name){
        return new XName(name);
    }
}

显式转换

将表示范围大的类型,转换成类型小的,有可能丢失数据,需要使用显式转换。

语法:

(类型)变量

整数类型的显式转换

static void Main(string[] args){
    int i = 100;
    short j = (short)i; //100
}

符合范围的显式转换也不丢失数据。

static void Main(string[] args){
    int i = 10000;
    short j = (short)i; //-31072
}

不符合范围的显式转换会导致截断,32位整数转换成16位时,只保留16位。

除非明确知道要进行截断,否则在转换前需要先进行范围判断。

浮点数与整数的显式转换

static void Main(string[] args){
    double i = 100.5;
    int j = (int)i; //100
}

将浮点数显式转换成整数时,浮点数的小数部分会被舍弃,只保留整数部分。

static void Main(string[] args){
    double i = 1e20;
    int j = (int)i;
}

由于整数的范围没有浮点数大,因此整数的范围可能无法保存浮点数,上面的代码会得到错误的结果。

小数与整数的显式转换

static void Main(string[] args){
    decimal i = 100.5;
    int j = (int)i; //100
}

小数显式转换成整数也只保留整数部分,而且有可能溢出。

浮点数和小数的显式转换

浮点数和小数之间也能够进行显式转换

static void Main(string[] args){
    decimal i = 100.5;
    double j = (double)i;
    decimal k = (decimal)j;
}

浮点数和小数直接的转换也可能有数据损失,也可能溢出。

整数和字符类型的显式转换

在.NET中,字符是UTF16的格式存储的,即16位的整数。字符和整数类型之间能够显式转换。

static void Main(string[] args){
    char ch = 'a';
    int j = (int)ch;
    char ch2 = (char)j;
}

自定义的显式转换

可以为结构和类提供显式转换。

public class BigInteger
{
    public static explicit operator int(BigInteger value)
    {
        return 0;
    }
}

安全的显式转换

显式转换可能会导致不在范围,默认情况,是不会报告错误的,这会得到意想不到的结果。

可以使用checked来进行溢出检查。

static void Main(string[] args){
    double i = 1e20;
    int j = checked((int))i;
}

上面的代码会报告OverFlowException

尽早地的得知错误,好过错误隐藏在看不见的地方。

手动转换

转换成字符串

基本类型都有一个方法ToString,用来到类型的字符串表示形式。

static void Main(string[] args){
    int i = 100;
    string s = i.ToString();
    double j = 3.14;
    string s2 = j.ToString();
}

部分类型的ToString方法还支持传递一个格式参数。

static void Main(string[] args){
    double j = 3.1415926;
    string s = j.ToString("f2");//保留两位小数
    string s2 = j.ToString("e2");//科学计数法
    int i = 100;
    string s3 = i.ToString("x");//16进制
}

不同的类型支持的格式也不同,具体需要参考文档。

由字符串解析

基本类型都有一个静态方法Parse,用来由字符串解析类型。

static void Main(string[] args){
    int i = int.Parse("100");
}

如果字符串的格式不正确,会报FormatException

可以使用TryParse方法,来进行判断解析。

static void Main(string[] args){
    int i;
    if(int.TryParse("100",out i)){
        //解析成功
    }
}

部分类型的解析还支持参数解析格式。

 int i = Int32.Parse("dd", NumberStyles.AllowHexSpecifier);//字符串数字是16进制

任意基本类型转换

C#提供了静态类Convert支持任意基本类型的转换。

static void Main(string[] args){
    string s = Convert.ToSting(100);
    int i = Convert.ToInt("200");
    bool flag = Convert.ToBoolean(5);
}

符合隐形转换类型的转换总是成功的。

符合显式类型的转换可能溢出或截断。

转换成字符串ToString是调用类型自身的ToString

以字符串作为参数是调用类型的Parse,可能会格式错误。

部分类型的转换使用了默认约定,比如int转换bool,0为false,非0为true

部分类型之间不支持转换,比如intDateTime之间。

Convert类虽然好用,但是要慎用。

类型转换器

System.ComponentModel.TypeConverter提供一个基本的类型转换器,用于进行任意类型转(通常是和字符串之间的转换)。

基本类型都实现类型转换器。

通过TypeDescriptorGetConverter静态方法来获取转换器。

 TypeConverter converter = TypeDescriptor.GetConverter(typeof(int));
 int i = (int)converter.ConvertTo(100L, typeof(long));
 int j = (int)converter.ConvertTo("0x100", typeof(string));

基本类型的转换器内部有的也是通过Convert来进行转换的,有的有额外的逻辑。

自定义类型转换器

[TypeConverter(typeof(PointConverter))]
public class Point
{
    public int X
    {
        get; set;
    }
    public int Y
    {
        get; set;
    }

    public override String ToString()
    {
        return X + "," + Y;
    }
}

public class PointConverter : TypeConverter
{
    public override Boolean CanConvertFrom(ITypeDescriptorContext context, Type sourceType)
    {
        return sourceType == typeof(string) || base.CanConvertFrom(context, sourceType);
    }

    public override Object ConvertTo(ITypeDescriptorContext context, CultureInfo culture, Object value, Type destinationType)
    {
        string s = value as string;

        string[] items = s.Split(',');

        if (items.Length != 2) throw new FormatException();

        return new Point
        {
            X = Int32.Parse(items[0]),
            Y = Int32.Parse(items[1])
        };
    }
}