衍生类和基类,我可以显式地设置基类吗?

22
public class SuperCar: Car
{
     public bool SuperWheels { get {return true; } }
}

public class Car 
{
     public bool HasSteeringWheel { get {return true;} }
}

我该如何为派生类Supercar设置基类?

例如,我想要像这样简单地设置Supercar的基类:

public void SetCar( Car car )
{
SuperCar scar = new SuperCar();
car.Base = car; 
}

基本上,如果我有汽车对象,我不想手动迭代每个汽车属性来设置超级汽车对象,我认为这是唯一的方法,但如果你能以其他方式做到,那就好多了。


3
不。简短原因:没有单独的基本对象。(object)this == (object)base始终为真。但是有其他方法可以通过反射(和其他手段)执行克隆/复制操作。也许描述一下真正想要的是什么 :) - user166390
我回顾了一下这个问题,对回答感到有些失望。我仍然有点困惑,为什么你不能在继承该类的对象上设置基类。当然,你不应该强制在继承的类上实现它,但是如果你恰好有一个实现 - 为什么不能设置它呢?例如,如果你正在创建一个从猴子和赛车继承的类,那么它既不是猴子也不是赛车 - 这是可以理解的。然而,如果你恰好有一个猴子和赛车的实现,并希望将这些实现插入 - 为什么不呢? - Watson
如果你没有有用的话要说,就不要说任何话。Eric Lippert对这个对话没有做出任何贡献。他没有解释为什么你不应该这样做或者为什么C#以这种方式工作,只是说它确实如此,他的权威足够好 - 不需要解释。请解释一下,感谢所有的鱼。 - Watson
@user190084:我认为你在这里有些不诚实。Eric给出了一个完全合理的解释:C#不使用原型继承,它使用古典继承,这只是编译时的特性,使其更容易实现(对于静态类型语言来说)。听起来问题真正存在的地方可能在别处。我看到你已经解释了实际用例。也许你应该编辑问题并提供这些信息,或许你会得到更好的答案。 - siride
如果Eric刚才说了你刚才说的话,我就不会再发表我的额外评论了。你刚刚给出了一个非常好的理由,解释了为什么C#使用经典继承。谢谢你。 - Watson
显示剩余4条评论
7个回答

15

我在子类中使用类似以下的代码,这对我来说可以很好地工作:

using System.Reflection;
.
.
.
/// <summary> copy base class instance's property values to this object. </summary>
private void InitInhertedProperties (object baseClassInstance)
{
    foreach (PropertyInfo propertyInfo in baseClassInstance.GetType().GetProperties())
    {
        object value = propertyInfo.GetValue(baseClassInstance, null);
        if (null != value) propertyInfo.SetValue(this, value, null);
    }
}

是的。这很完美。 - Watson

4

如果我正确理解了你的问题(但我并不完全确定),那么你可以通过以下方式实现所需的行为:

class Car {
    public bool CarProperty { get; set; }
    // regular constructor
    public Car() {

    }
    // "copy" constructor
    public Car(Car c) {
        CarProperty = c.CarProperty;
    }
}

class SuperCar : Car {
    public bool SuperCarProperty { get; set; }
    // regular constructor
    public SuperCar() {
    }
    // "copy" constructor
    public SuperCar(Car c) : base(c) {
        SuperCar sc = c as SuperCar;
        if(sc != null) {
            SuperCarProperty = sc.SuperCarProperty;
        }
    }

然后您可以这样做:
public void SetCar(Car car) {
    SuperCar scar = new SuperCar(car);
}

请注意,在“复制”构造函数中,您必须非常小心,不要以某种方式复制属性,使得两个对象共享相同的成员(引用),当它们不应该共享时。
不过,我必须问一下,您的目标是什么?

我的目标很简单。在现实生活中,超级跑车可能会有数百个属性。所以假设我现在维护一个超级跑车的数据库。现在,我想从超级跑车继承,但我想为了方便而传递已经创建的超级跑车基类。我不想在已经创建了基类型的情况下手动设置100个属性。 - Watson
听起来你需要将超级汽车分解成较小的对象。然后可以共享在超级汽车之间相同的对象。 - siride
我更关心我对C#中继承的理解。在我的看法中,如果A类派生自B类,那么你应该能够在A上设置B。因此,如果你有一个A类的实例,你应该能够说A.B = new B(); - Watson
我认为你对继承的理解不够深入。继承是关于为一组对象定义形式,而不是为特定对象定义具体细节。如果要做后者,你应该使用组合。 - siride
我会进一步调查这个问题。非常感谢您的反馈。非常感谢。 - Watson
显示剩余3条评论

2

您只能复制另一个类的内容,但不能直接设置它。请参见下面的示例,使用所谓的复制构造函数。

class Car
{
    string model;
    public Car(string model) { this.model = model; }
    protected Car(Car other) { this.model = other.model; }
    string Model { get; set; }
}

class SuperCar : Car
{
    public SuperCar(Car car) : base(car) { }
    public SuperCar(string model) : base(model) { }
    bool IsTurbo { get; set; }
}

关键在于构造函数声明后的关键字base()

这很有趣,但它并没有真正解决迭代30个属性的问题,除非我完全错过了什么。 - Michael Sefranek
如果需要手动设置属性,则此答案更好地解释了如何最好地使用复制构造函数。 - John Alexiou

2

这是不可能的。

您需要手动设置属性。


假设我有一个人类,当然有成千上万的数据项代表这个人类。人类定义了一万个属性。现在,我有一个人ID与特定的人类相关联,我想从中派生出一个名为“John”的类,该类继承自人类。现在我知道一个特定的人ID,我想传入它作为“John”的基础。 - Watson
你可以使用包装器而不是继承。 - SLaks

1

总体来说,有很多有用的评论。我认为pst给出了简短的答案,我认为这是正确的:

不,简短的原因是:没有单独的基对象。(object)this ==(object)base始终为真。但是可以通过反射(和其他手段)执行克隆/复制的方法。也许描述一下真正想要的是什么

因此,他使用automapper工具的建议也非常有用,基本上就是我正在寻找的。


0
首先,每个SuperCar对象都与其他对象不同。继承帮助您定义相关对象的共同行为,但这并不意味着它们是相同的对象。每个类型的对象都有自己的构建过程。在创建子对象之前,根据继承层次结构创建基类对象。如果您希望为所有SuperCar对象使用公共属性,则需要在SuperCar实例中维护一个单独的Car对象实例,将公共Car对象分配到SuperCar中的Car对象中,并覆盖从基本Car对象派生的属性并将其重定向到内部Car对象的props。
public class SuperCar: Car
{
     public bool SuperWheels { get {return true; } }

     Car carInstance = null;
     public void SetCar( Car car )
     {
         carInstance = car; 
     }
}

但我仍然相信,以你想要的方式进行设计中存在一些问题。如果您可以让我们了解为什么要这样做的更大画面,我们可能会提出更好的设计来满足您的需求。


0

如果您想要比复制反射属性更多的控制权,请尝试应用建造者模式。T可以是任何从BaseClass派生的类。

 public static T BuildNew<T>(BaseClass baseClass) where T : BaseClass, new()
 {
    return new T
    {
        Property1 = baseModel.Property1,
        Property2 = baseModel.Property2,
    };
 }

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