加入收藏 | 设为首页 | 会员中心 | 我要投稿 李大同 (https://www.lidatong.com.cn/)- 科技、建站、经验、云计算、5G、大数据,站长网!
当前位置: 首页 > 百科 > 正文

c# – 如何在双层次结构中正确表示继承?

发布时间:2020-12-16 01:55:50 所属栏目:百科 来源:网络整理
导读:假设我们有两个继承层次结构,其核心: Car - SportsCar - SuperCar 和 Engine - TurboEngine - FormulaOneEngine 汽车有发动机. SportsCar有TurboEngine和SuperCar有FormulaOneEngine.问题是如何在C#中正确表示这一点.假设我们这样做: class Car { Engine E
假设我们有两个继承层次结构,其核心:

Car -> SportsCar -> SuperCar

Engine -> TurboEngine -> FormulaOneEngine

汽车有发动机. SportsCar有TurboEngine和SuperCar有FormulaOneEngine.问题是如何在C#中正确表示这一点.假设我们这样做:

class Car {
  Engine Engine;
  int HeadLamps;
}
class SportsCar: Car {
  TurboEngine TurboEngine;
  int Ailerons;
}
class SuperCar: SportsCar {
  FormulaOneEngine FormulaOneEngine;
  int FlyingSaucers;
}

这解决了问题,但它看起来很丑陋!例如,SuperCar现在有三个成员,它们通常指向同一个实例(如果他们不这样做则更糟!)并且看起来也没必要.对于4级,5级或更多级别的深层次结构,这看起来非常难看:

SuperCar.Engine
SuperCar.SportsEngine
SuperCar.FormulaOneEngine

理想情况下,所有类型的汽车应该只有一个名为Engine的成员,但它应该是不同的类型,具体取决于汽车:

Car.Engine
SportsCar.Engine //of type TurboEngine
SuperCar.Engine //of type FormulaOneEngine

此外,这应该支持多态,所以我可以

List<Car> x = ...
x.Add(myCar);
x.Add(mySportsCar);
x.Add(mySuperCar);
foreach(Car c in x)
{
  x.Engine ...
}

所以使用“新”成员就出局了.我还希望能够直接调用每种引擎类型的特定方法:

class Engine { int Capacity; }
class TurboEngine: Engine { int TurboCharger; }
class FormulaOneEngine: TurboEngine { int JetFuel; }

myCar.Engine.Capacity = ....
mySportsCar.Engine.TurboCharger = ...
mySuperCar.Engine.JetFuel = ...

此外,我将能够使用正常的继承好东西:

myCar.HeadLamps = ...
mySportsCar.HeadLamps = ....
mySportsCar.Ailerons = ....
mySuperCar.HeadLamps = ...
mySuperCar.Ailerons = ....
mySuperCar.FlyingSaucers = ....

任何想法如何重构这个以达到目的,也看起来漂亮?实际代码可能使用4,5或更多级别的继承链.我错过了一些明显的或者可能是一些技巧吗?

解决方法

这是一个典型的通用案例:

编辑再一次 – 仍然是相同的概念,但继承链完全存在.您必须拥有隐藏属性(新)才能满足您的需要,但是由于您正在实现ICar界面,因此在获得混合集合时仍然可以获得基本属性.我认为这是你能做的最好的事情.

public interface ICar
{
    IEngine Engine { get; set; }
}

public abstract class BaseCar<T>
    : ICar
    where T : IEngine
{
    public T Engine { get; set; }
    IEngine ICar.Engine { get { return Engine; } set { Engine = (T)value; } }
}

public class Car : BaseCar<Engine>,ICar { }

public class SportsCar : Car,ICar
{
    IEngine ICar.Engine
    {
        get { return Engine; }
        set { Engine = (TurboEngine)value; }
    }

    public new TurboEngine Engine
    {
        get { return (TurboEngine)base.Engine; }
        set { base.Engine = value; }
    }
}
public interface ISportsCar<T> : ICar where T : TurboEngine { }

public class SuperCar : SportsCar,ISportsCar<FormulaOneEngine>
{
    public new FormulaOneEngine Engine
    {
        get { return (FormulaOneEngine)base.Engine; }
        set { base.Engine = value; }
    }
}

public interface IEngine { }
public class Engine : IEngine { }
public class TurboEngine : Engine { }
public class FormulaOneEngine : TurboEngine { }

你现在可以这样做:

var cars = new List<ICar>();
cars.Add(new Car());
cars.Add(new SuperCar());
cars.Add(new SportsCar());

请记住,Engine属性在此上下文中将是IEngine接口类型,这意味着您将无法访问每个类的唯一属性,并且如果您尝试分配错误的对象,则可能会遇到运行时异常到那个属性.但是,如果你说:

var mySportsCar = new SportsCar();
mySportsCar.Engine // this will be strongly typed as TurboEngine

(编辑:李大同)

【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容!

    推荐文章
      热点阅读