为了方便演示,这里一共有两个简单的类
父类:动物类(Animal)
/// <summary>
/// 动物类-父类
/// </summary>
public class Animal
{
/// <summary>
/// 脚
/// </summary>
public string Foot { get; set; }
/// <summary>
/// 头
/// </summary>
public string Head { get; set; }
}
子类:狗类(Dog)
/// <summary>
/// 狗类-继承动物类
/// </summary>
public class Dog : Animal
{
/// <summary>
/// 尾巴
/// </summary>
public string Tail { get; set; }
/// <summary>
/// 构造函数
/// </summary>
public Dog()
{
Head = "狗头";
Foot = "狗腿";
Tail = "狗尾巴";
}
}
|
第一步:如果我们将Dog类转换为Animal类
Dog dog = new Dog();
//转换为动物类---子类转换为父类
Animal animal = dog as Animal;
这个按照我们一贯的想法,应该就是舍去子类的扩展属性(这里是Tail),只保留父类中的属性(Foot,Head)。那么结果转换后的Animal类应该这样的
第二步:而如果我们继续把这个对象重新转换为Dog类 Dog dog2 = animal as Dog;
Dog类应该是这样的
但是事实上,在第一步把Dog
转换为Animal
时,Animal
没有把Tail
这个字段抛去,如下图
但是,在VS的智能提示中我们并不能访问Tail
属性,直接使用编译也会报错
而且从上面的结果中,我们也能猜出第二步的实际结果,Dog
类中Tail
并不是NULL
第三步:试试父类转换为子类
很明显,父类并不能转换成子类,虽然编译可以通过,但是运行时会抛出System.InvalidCastException
异常,当然这里使用as
关键词可以避免这一异常,结果返回NULL
那么父类怎么转换成子类呢?对于一些相对简单的类,我们可以通过遍历的方式逐个赋值
Animal animal = new Animal
{
Foot = "脚",
Head = "头"
};
Dog dog = new Dog
{
Foot = animal.Foot,
Head = animal.Head,
};
如果属性多的时候,使用这种方法就麻烦了,这时可以使用反射
遍历属性来设置对应的值
Animal animal = new Animal
{
Foot = "脚",
Head = "头"
};
Dog dog = new Dog();
//遍历Animal类的公共属性
foreach (PropertyInfo item in typeof(Animal).GetProperties())
{
item.SetValue(dog, item.GetValue(animal));
}
结果:
更多有关反射的内容可以参考官方文档
到这里结论应该清楚了
- 子类可以转换为父类,并且子类中的扩展属性会被父类“隐性”保留,但不可访问(编译出错),以便父类重新转换为子类。
- 父类不可转为子类,这里倒是很好理解,毕竟多变少可以,少变多就不行了。