我可以实例化继承超类实例的类吗?

4
我正在使用C#,但我认为这是一个非常普遍的面向对象问题。假设我有一个名为Animal的类,它具有属性如LegCount、EyeCount、HasFur、EatsMeat等。
假设我有一个Animal实例a,其中LegCount设置为4,EyeCount设置为2。
现在,我想创建一个类型为Dog的实例d,它继承自Animal。我想用a的所有值来初始化d。我意识到我可以创建一个构造函数或其他方法,该方法将采用Animal并复制所有值,然后输出一个新的Dog,但我希望有一些面向对象的原则/技巧可以帮助我。
简单来说,我想做的是:
创建Dog的新实例d,其所有起始值都来自a。关键是“全部”,而不是逐个指定每个属性。
当您设计一个继承自其他类的类时,您不需要列出它继承的所有成员。它只是继承了它们所有。因此,我想知道是否可以在实际实例上“继承值”。

2
就纯面向对象编程而言,我认为“创建一个构造函数或其他方法,该方法将采用Animal并生成具有所有复制值的新Dog”实际上就是诀窍。您可以定义形式为Dog(Animal a)的构造函数,而不是Dog(int LegCount,int EyeCount,...)。您仍然可能需要自己执行一对一的赋值,但从面向对象的角度来看,这就是“诀窍”,据我所知。 - asfallows
似乎我应该能够只用一两个关键词说“这是一个动物,给我最全面的狗”的对象。 - Chris
1
我同意。顺便说一下,io可以在某种程度上做到这一点。你实际上可以从一个实例中派生子类。http://iolanguage.com/(我知道这对C#没有帮助,但是io很有趣) - asfallows
4个回答

20
你想要的功能被称为“原型继承”或“面向原型编程”。C#不支持这个功能,所以在那里你就没有机会了。
如果你的架构基本上需要这个功能,可以考虑使用支持原型继承的语言。JavaScript是最常用的原型继承语言。
如果你不小心处理原型继承,可能会非常棘手。如果你对这个主题感兴趣,请参阅我的文章,其中介绍了在JScript中使用原型继承时可能遇到的一些奇怪情况:

http://blogs.msdn.com/b/ericlippert/archive/2003/11/06/53352.aspx


1
我认为我基本上不需要这个功能。我仍在学习C#和OO,并希望确保在做其他事情之前,我没有跳过一些内置的方法,导致未来的开发人员可能会看我的代码并想“但他为什么不只是...”。感谢您给我提供了我所思考的东西的名称。现在我可以阅读所有相关信息。我也会查看您的博客文章。谢谢! - Chris

5

你不能使用某些C#语言结构来完成你所要求的功能,你必须手动编写映射或委托代码。或者,可以查看AutoMapper


1
阅读完这里的所有内容后,感觉只需复制几个属性就是正确的方法,但我很感激这个答案,因为它帮助我解决了一个完全不同的问题!在序列化某些对象时,我会出现这些循环引用警告,而这将帮助我管理简化的 DTO! - Chris

1
public class Animal
{
    public Animal(Animal otherAnimal)
    {
        if (otherAnimal == null)
            throw new ArgumentNullException("otherAnimal");

        foreach (System.Reflection.PropertyInfo property 
            in typeof(Animal).GetProperties())
        {
            property.SetValue(this, property.GetValue(otherAnimal, null), null);
        }
    }
}

然后只需从您的Dog(Animal otherAnimal)构造函数中调用此Animal构造函数

但是,您仍应认真考虑一下类的设计,并将Animal作为抽象类。因为您想象一下Animal类的实例是什么..


1

1
+1 我也在考虑这个方向,但忘记了装饰器模式。对于这种情况,我认为它会很好地工作,使用像Quadruped、Carnivore等包装器。 - asfallows
你需要某种复制构造函数,否则在装饰时修改使用的项可能会导致问题,如果仍在使用Animal实例,则可能会出现问题。 - John Kalberer
@John,原始对象不能作为“内部”对象保留,然后扩展是装饰器合同的一部分吗? - Martin
是的,它可以被保留下来,但由于Animal 'a'是一个引用,如果他想在其他地方继续使用'a',它可能会导致问题。修改'd.LegCount'也将修改'a.LegCount'。如果OP不再需要'a',那么你的答案是正确的。 - John Kalberer
是的,这就是装饰器模式的全部含义。扩展功能,而不是修改现有功能。 - Martin

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接