说起类型转换大家很容易的就会联想到将int类型转换成float类型或者是将double类型转转成int类型之类的转换。当然这可能是大多数人最先接触到的转换方式,也是最简单的转换方式。所谓转换就是从现有类型的值创建一个新的值,对于大多数面向对象的语言而言,因为多出了"类"这个概念,所以类型转换并不仅仅是基础类型(int、float、string等)之间的转换。.NET作为一个承载平台而言自然是需要提供适应多种情况的类型转换方式的,因此本文就结合自己的理解对.NET下的类型转换作一个简单的总结,如有错误,请各位不吝赐教!
一、.NET自动支持的类型转换
- 基类型和派生类型之间的相互转换
- 接口对象和实现接口类型的对象之间的相互转换
.NET除了自动支持基础类型之间的转换外还自动支持以上两种类型之间的转换。
至于基类、派生类和接口等概念想必无须过多赘述了。我们先定义一个简单的IPeople接口以及实现该接口的People类,然后再定义一个继承自People的ChinesePeople类。
public interface IPeople
{
string Name { get; set; }
int Age { get; set; }
}
public class People:IPeople
{
public
string Name { get; set; }
public
int Age { get; set; }
public
int Height { get; set; }
}
public class ChinesePeople : People
{
public
string Country { get; set; }
}
由于.NET已经自动支持了以上两类的转换,因此我们可以作如下操作:
People people = new People();
ChinesePeople chinesePeople = new ChinesePeople();
people = chinesePeople;//派生类隐式转换成基类
chinesePeople = (ChinesePeople)people;//基类显示转换成派生类
IPeople ip = people;//实现接口的对象隐式转换成接口对象
people = (People)ip;//接口对象显示转换成实现接口的对象
以上两种转换都是比较简单的类型转换方式,也是在编程中会经常用到的。
二、基类型之间的转换:Convert
Convert是一个与语言无关的静态类,它为我们提供了一组类似ToXXX()形式的方法使得类型之间的转换变得非常简单。使用起来也很简单,例如:
Note:Convert类官方文档https://msdn.microsoft.com/zh-cn/library/system.convert(v=vs.110).aspx
三、自定义类型之间的转换:implicit(扩大、隐式转换)和explicit(缩小,显示转换)
上文已经说过,通过继承或者实现接口的方式我们可以对类型进行显示或隐式转换,那么问题来了,如果两个类型之间没有继承或者接口实现的关系,要怎么在这两个类型之间进行隐式或者显示转换呢?比如说我们再定义一个类型Dog
public class Dog
{
public
string Name { get; set; }
public
int Age { get; set; }
}
如果不进行任何操作直接将Dog类型的变量转换成People或者ChinesePeople类型的变量编译器肯定会抛出异常,就像下面这样,因为编译器无法将Dog类型的变量隐式或者显示的转换成People类型的变量
大家也可以这样理解,狗和人虽然都是动物,并且两者都有名字、年龄、身高等属性,所以从客观上来讲两者是不同的种类,不做任何操作的话是不能相互转换的。但是从主观来讲,张三做了对不起李四的事,李四可能就会认为张三他不是个人,他是条狗。这种情况是因为张三"做了一些事或者一些操作",所以李四才觉得他"可以"是条狗。下面就引入两个关键字implicit和explixit:
- Implicit:扩大(隐式)转换,当前类型比目标类型具有更小的范围或成员列表(可以理解为基类比派生类具有更少的成员列表)
- explicit:收缩(显示)转换,当前类型比目标类型具有更大的范围或成员列表(可以理解为派生类比基类具有更少的成员列表)
首先我们来看implicit关键字,implicit关键字可以定义类型的隐式转换,即如果要从People类型隐式转换成Dog类型的话我们需要对Dog类进行一些操作。
/// <summary>
/// 定义从People类型隐式转换成Dog类型的操作
/// </summary>
/// <param name="people">People类型的变量,保存People类型的数据</param>
public static implicit operator Dog(People people)
{
Dog dog = new Dog();
dog.Name = people.Name;
dog.Age = people.Age;
return dog;
}
上面的操作很简单,就是将People类型的一些数据赋值给Dog类型的变量,有了如上操作,我们就可以将People类型的变量隐式转换成Dog类型的变量而不会发生错误。
同理,一条可爱的小狗在某些人的眼里可能就像自己的亲人一样,因此狗"也可以当作"是人,但是也要做一些额外的"操作",比如给狗穿上一件好看的衣服或者剪个时髦的发型。。。所以狗需要"显示"转换成人。因此我们对People类型进行一些变换使得狗可以显示的转换成人。
public class People : IPeople
{
public
string Name { get; set; }
public
int Age { get; set; }
public
int Height { get; set; }
/// <summary>
/// 定义从Dog类型隐式转换成People类型的操作
/// </summary>
/// <param name="dog">Dog类型的变量,保存Dog类型的数据</param>
public static explicit operator People(Dog dog)
{
People people = new People();
people.Name = dog.Name;
people.Age = dog.Age;
people.Height = 111;
return people;
}
}
有了上面的操作我们就可以将Dog类型变量显示转换成People类型的变量
Note:implicit和explicit两个关键字均是对"目标类型"进行操作,比如要将People类型隐式转换成Dog类型的话就要对Dog类型进行操作
四、IConvertible:自定义类型到CLR基类型之间的转换
上面已经介绍了基类型和自定义类型之间的相互转换,那么问题又来了,怎样把一个自定义类型转换成基类型?这种需求虽然不常见,但.NET作为一个平台而言自然是要尽量满足各种需求的。因此它为我们定义了一个IConvertible接口,该接口定义了向所有基类型转换的方法。
不仅如此,该接口还定义了一个返回实现类型的TypeCode方法以及将该类型转换成另一个类型的通用方法ToType。在实现向基类型转换的方法中我们就可以用到Convert静态类,因此IConvertible接口和Convert静态类的组合使得我们可以方便的定义自定义类型到基类型之间的转换。
Note:IConvertible接口的官方文档https://msdn.microsoft.com/zh-cn/library/system.iconvertible(v=vs.110).aspx
五、TypeConverter
除了上述几种类型转换方式之外,我们还可以通过TypeConverter为自定义类型定义转换器,通过使用TypeConverterAttribute使得自定义类型与转换器相关联。这种方式在WPF中比较常见。使用如下:
1.先定义一个类型转换器,转换器只重写了ConvertFrom和ConvertTo两个方法
public class PeopleConverter : TypeConverter
{
public override
object ConvertFrom(ITypeDescriptorContext context, CultureInfo culture, object
value)
{
if (value is string)
{
string[] datas = ((string)value).Split(‘ ‘);
People people = new People();
people.Name = datas[0];
people.Age = Convert.ToInt32(datas[1]);
people.Height = Convert.ToInt32(datas[2]);
return people;
}
return base.ConvertFrom(context, culture, value);
}
public override
object ConvertTo(ITypeDescriptorContext context, CultureInfo culture, object
value, Type destinationType)
{
if (destinationType == typeof(string))
{
People people = value as People;
return people.Name + " " + people.Age + " " + people.Height;
}
return base.ConvertTo(context, culture, value, destinationType);
}
}
2.为自定义类关联转换器
经过上面两个步骤我们就可以这样来使用转换器:
输出如下:
TypeConverter类的具体用法参照官方文档https://msdn.microsoft.com/zh-cn/library/system.componentmodel.typeconverter(v=vs.110).aspx