从子(派生)类到父(基)类

时间:2015-05-19 06:58:49

标签: c#

假设我有两个以下的课程

public class Animal
{
    public string name { get; set; }
}

public class Cat: Animal
{
   public int age { get; set; }
   public string type { get; set; }
}

现在我想转换我的派生类" Cat"匹配属性(例如姓名)到我的基类" Animal"隐式转换如下。

            Cat cat = new Cat();
            cat.name = "diana";
            cat.age = 2;
            cat.type = "Siamese-American Shorthair";

            Animal animal = new Animal();

            animal = (Animal)cat;
             // or
            animal = cat as Animal;

所以在进行上述编码时它会正常工作并且会在Animal类对象中隐式获取name属性但是如果我检查Animal类的对象,那么动物实际上是包含Cat类的对象,它是cat而不是实际得到的对象动物类。

所以请帮助我解决这个问题,这样我就可以直接将我的子类属性隐式转换为匹配的类属性,并使用正确的父类对象。

5 个答案:

答案 0 :(得分:3)

即使你只看动物,猫也永远是猫。您无法删除对象的实际类型;将它转换为父类型只会影响您存储它的变量,但底层对象保持不变。

Cat cat = new Cat(); // cat is a cat

Animal catAnimal = cat; // a cat is also an animal
Console.WriteLine(catAnimal.GetType()); // still a cat

Cat newCat = (Cat)catAnimal;

Console.WriteLine(newCat == cat); // the same cat
Console.WriteLine(animal == cat); // the same cat

答案 1 :(得分:2)

首先,这是不是隐式转换,而是一个明确的转换。 隐式转换示例如下:

int x = 123;
string y = "asdf" + x; // this is the implicit conversion.

第二次,你不能“uncat”这只猫。即使您的参考类型为cat

,它仍然是object

第三,来自任何类的任何对象都将保留其父类的属性和字段,除非它们被声明为private,因此将猫投射到动物以获取它的名称财产是多余的。

那么,这样的演员会有用吗?
答案是肯定的,它可能在以下情况下:

  • 您的派生类使用new关键字隐藏基类功能。
  • 您的派生类显式实现了interface,隐式实现与显式实现不同。

以下是这些情况的示例:

将对象转换为它的基类以使用属性或方法是将派生类中的属性或方法声明为new

public class Base {

    internal virtual string X() {
        return "Base";
    }
}
public class Derived1 : Base
{
    internal new string X()
    {
        return "Derived 1";
    }
}

public class Derived2 : Base 
{
    internal override string X()
    {
        return "Derived 2";
    }
}

Derived1 a = new Derived1();
Base b = new Derived1();
Base c = new Derived2();
Console.WriteLine("Derived1 as Derived1: "+ a.X()); // Derived1 as Derived1: Derived 1
Console.WriteLine("Derived1 as Base: " + b.X()); // Derived1 as Base: Base
Console.WriteLine("Derived2 as Base: " + c.X()); // Derived2 as Base: Derived 2

See fiddle here

当一个对象使用隐式实现重载显式实现时,将对象转换为它实现的 interfaces 之一。

public interface IBlabla {
    string bla();
}

public class BlaBla : IBlabla 
{
    public string bla() {
        return "implicit";
    }

    string IBlabla.bla()
    {
        return "EXPLICIT";
    }
}

BlaBla Myclass = new BlaBla();    
Console.WriteLine(Myclass.bla()); // implicit
Console.WriteLine(((IBlabla)Myclass).bla()); // EXPLICIT

See fiddle here

答案 2 :(得分:2)

您无法更改对象类型。正如Yuval Itzchakov已经提到的,你需要创建一个Animal类型的实例。您只能为Animal类创建某种复制构造函数,将所有属性和变量从给定的Animal复制到新的:

public Animal(Animal animal) {
    this.Name = animal.Name;
    // further variables and properties to reset the state exactly to the state of the given animal
}

现在,您可以从每个派生类型创建类型Animal的实例,如下所示:

Animal ani = new Animal(cat);

然而,这对我来说仍然听起来像设计缺陷(可能是XY-problem)。如果您需要访问cat的Name - 属性,则不需要转换为其基类型。

答案 3 :(得分:1)

如果真的想要,你可以按照

的方式做点什么
 internal class Program
{
    public class Animal
    {
        public string Name { get; set; }           
    }

    public class Cat : Animal
    {
        public int Age { get; set; }
        public string Type { get; set; }
    }

    public static void Main()
    {
        var cat = new Cat();
        cat.Name = "Puss";

        var animal = cat.ToBaseClass<Animal, Cat>();

        Debug.Assert(!(animal is Cat));
        Debug.Assert(animal.Name == "Puss");

    }
}

public static class ReflectionHelper
{
    public static TBase ToBaseClass<TBase, TDerived>(this TDerived from) 
        where TBase : new()
        where TDerived : TBase
    {
        var result = new TBase();

        foreach (PropertyDescriptor propertyDescriptor in TypeDescriptor.GetProperties(result))
        {
            propertyDescriptor.SetValue(result, propertyDescriptor.GetValue(from));
        }

        return result;
    }
}

......但这会很难看;)

答案 4 :(得分:0)

感谢所有帮助我解决问题的人,我非常重视每个人的答案和评论。 我还找到了另一种可能对某人有用的解决方案。由于这个问题是关于从子级到父级的相同属性的转换,我们可以使用AutoMapper,它可以对从子级到父级或父级到子级的任何类进行转换。首先,您可以从给予链接的nuget下载或更新AutoMapper,并在项目或应用程序中添加作为参考。

https://www.nuget.org/packages/AutoMapper/

现在根据我的问题,如果我想将属性从子类转换为父类,而不是使用AutoMapper进行编码,则如下所示。

     Mapper.CreateMap<Cat, Animal>();
     Animal animal = Mapper.Map<Animal>(cat);

我希望这个解决方案能够解决我的问题。