简体   繁体   English

从子类到父类的隐式对话

[英]Implicit conversations from child(derived) class to parent(base) class

suppose I have two following classes 假设我有以下两个班

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

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

and now I want to convert my derived class "Cat" match property(eg Name) to my base class "Animal" with implicit conversion as following way. 现在我想通过隐式转换将派生类“ Cat”的match属性(例如Name)转换为基类“ 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;

so while doing above coding it will work fine and will get name property implicit in Animal class object but if I check object of Animal class that is animal actually contains the object of Cat class that is cat and not actually get the object of Animal class. 因此,在执行上述编码时,它会很好地工作,并且会获得动物类对象中隐含的name属性,但是如果我检查动物类的对象,则该动物实际上包含的是Cat类的对象是cat,而实际上并未获得动物类的对象。

So please help me to come over this situation so I can directly implicit convert my child class property to my matched class property with proper parent class object. 因此,请帮助我解决这种情况,以便我可以使用适当的父类对象将我的子类属性直接隐式转换为匹配的类属性。

A cat will always be a cat, even if you are only looking at animals. 即使只看动物,猫也永远是猫。 You cannot remove the actual type of an object; 您不能删除对象的实际类型。 casting it to a parent type will only affect the variable you store it to but the underlying object remains the same. 将其强制转换为父类型将只影响将其存储到的变量,但基础对象保持不变。

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

First , this is not an implicit conversion, but an explicit one. 首先 ,这不是隐式转换,而是显式转换。 An implicit conversion example is this: 一个隐式转换示例是这样的:

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

Second , you can't "uncat" the cat. 第二 ,你不能“解开”猫。 it will still be a cat even if your reference is of type object , 即使您的引用是object类型的,它也仍然是cat

Third , any object from any class will keep the properties and fields of it's parent class, unless they are declared as private , so casting a cat to an animal to get it's name property is redundant. 第三 ,任何类中的任何对象都将保留其父类的属性和字段,除非将它们声明为private ,所以将猫放到动物上以获取其name属性是多余的。

So, can such a cast be useful? 那么,这样的转换有用吗?
The answer is yes, it might, in the following situations: 答案是肯定的,在以下情况下可能会:

  • Your derived class hides base class functionality using the new keyword. 您的派生类使用new关键字隐藏了基类功能。
  • Your derived class explicitly implements an interface , and the implicit implementation is different then the explicit one. 您的派生类显式实现一个interface ,隐式实现不同于显式interface

Here are examples of these situations: 以下是这些情况的示例:

Casting an object to it's base class to use a property or method is when the property or method in the derived class is declared as new : 当派生类中的属性或方法声明为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 在这里看到小提琴

Casting an object to one of the interfaces it implements, when the class overloads the explicit implementation with an implicit one. 当类使用隐式对象重载显式实现时,将对象强制转换为它实现的接口之一。

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 在这里看到小提琴

You cannot change an objects type. 您不能更改对象类型。 As Yuval Itzchakov already mentioned you need to create an instance of type Animal . 正如Yuval Itzchakov已经提到的那样,您需要创建一个Animal类型的实例。 You may only create some kind of copy-constructor for your Animal-class that copied all properties and variables from the given Animal to the new one: 您只能为Animal-class创建某种复制构造函数,该结构将所有属性和变量从给定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
}

Now you can create an instance of type Animal from every derived type like so: 现在,您可以从每个派生类型创建Animal类型的实例,如下所示:

Animal ani = new Animal(cat);

However that still sounds like a design-flaw (propbably an XY-problem ) to me. 然而,对我来说,这仍然听起来像是设计缺陷(可能是XY问题 )。 If you need to access the Name -property of your cat you won´t need to cast to its base-type. 如果您需要访问猫的Name -属性,则无需将其强制转换为基型。

If you really wanted to, you could do something along the lines of 如果您真的想,可以按照以下方式做一些事情

 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;
    }
}

... but it would be pretty ugly ;) ...但是那会很丑;)

Thanks to all of you who help me to solve my problem and I take everyone answers and comments very seriously. 感谢所有帮助我解决问题的人,我非常重视每个人的答案和评论。 I have also find another solutions which may be useful to someone. 我还发现了另一种可能对某人有用的解决方案。 As this questions is regarding conversion with same property from child to parents class, we can use AutoMapper which can do conversion for any class from child to parent class or parent to child class. 由于此问题是关于从子类到父类具有相同属性的转换,因此我们可以使用AutoMapper,它可以对从子类到父类或父子到子类的任何类进行转换。 For that first you can download or update AutoMapper from nuget at give link and add as reference in your project or application. 首先,您可以从nuget的给定链接下载或更新AutoMapper,并在您的项目或应用程序中添加为参考。

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

Now as per my question if I want to convert property from child to parent class than coding using AutoMapper functionality would be as below. 现在,按照我的问题,是否要将子类的属性转换为父类,而不是使用AutoMapper功能进行编码,如下所示。

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

I hope this solutions will work for you as it has solved my issues. 我希望该解决方案能够解决您的问题,因此对您有用。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM