如何创建 class 的(多态性)collection/list/array,其中每个都可能具有一些不同的属性

How to create a (Polymorphism) collection/list/array of a class where each one may have some different properties

如果我想为游戏创建汽车引擎设计,我将执行以下操作:

基地class:

public class EngineParts {
        public string name;
        public int ID; 
        public GameObject Mesh; 
        public Vector3 Position; 
        public Quaternion Rotation; 
        public string Description;
        public float new_value; // the brand new price of it
}

然后我会得到继承自它的 classes:

public class Rods : EngineParts
    {    
    }

public class Pistons : EngineParts
    {
        public float Size=51;
        public float Compression=51;
    }

public class Turbo : EngineParts
    {
        public float maxboostpressure;
        public float minboostpressure;
        public float MaxOperatingRPM;
        public float MinOperatingRPM;
        public float AirToEngineRatio;
        public float wasteGatePressure;
    }

这里重要的是所有汽车零件共享一些在 Base class 中的公共值,这些值是名称、ID、网格、位置、旋转..等

它们还有其他更具体的部件本身的值,例如 Turbo 有 maxboostpressure,它决定了涡轮可以处理的最大增压压力。

现在在实际游戏中我需要能够将零件作为一个集合来使用

public EngineParts[] Part = new EngineParts[3];

Part[0] = new Rods();
Part[1] = new Pistons();
Part[2] = new Turbo();

因此,我可以在需要时遍历所有零件,因为它们都是 EngineParts.

类型

但是当我试图给最大值 maxboostpressure 赋值时,我做不到。

   //Note: Part[1] here is pistons
    Part[1].name = "SportPiston"; // this will work since it is type of EngineParts
    Part[1].maxboostpressure = 5.0; // this will not work

这是因为它的类型是 EngineParts

不过我可以说:

Rods rd = new Rods();
Pistons pt = new Pistons();
Turbo tb = new Turbo();

pt.name = 5; // this will work
pt.maxboostpressure = 5; // this will work

现在它们确实共享来自 Base class 的相同数据,但我不能将 Rods、Pistons、Turbo 放在一个集合中以循环遍历或将它们传递到一个适用于所有它们的函数中。

所以

这里是问题

我怎样才能最好地做到这一点?
1- 将发动机的所有部件合二为一 collection/List
2- 能够以最少的编码在每种类型的零件上存储额外的数据。

我一直在阅读
抽象 类、重载、多态和继承 来解决这个问题,但仍然有一些我必须想念的东西,所以如果有人能指出我正确的方向,那就是非常感谢。

提前致谢

问题是,你怎么知道列表中的第 3 项是特定的子class?

你目前知道,因为你专门为它分配了数组中的一个位置,但是你应该随时处理这个问题,任何子class都可以在数组中的任何位置。

考虑到这一点,您需要检查数组项的类型,然后在对其进行处理之前对其进行转换。

if(Part[1] is Turbo)
{
   ((Turbo)Part[1]).maxboostpressure = 5;
}

有几种方法可以测试类型:

typeof 采用类型名称(您在编译时指定)。

GetType 获取实例的运行时类型。

is returns 如果实例在继承树中则为真。

您可以使用 "is" 和 "as" 运算符。

var list = new List<EngineParts>();

// add some parts to the list here...

foreach(var part in list) {
  if(part is Turbo) {
    (part as Turbo).maxboostpressure = 123;
  }
}

试试这样的转换:

Piston p = Part[1] as Piston;

如果 Part[1] 不是活塞,则 p 将为空。

然后继续

if(p!=null)
    doSomethingHere;

最好的方法是将数组分成子类的各个部分。使用 linq

EngineParts[] Part = new EngineParts[3];

Part[0] = new Rods();
Part[1] = new Pistons();
Part[2] = new Turbo();

Rods[] rods = Part.Where(x => x is Rods).Cast<Rods>().ToArray();
Pistons[] position = Part.Where(x => x is Pistons).Cast<Pistons>().ToArray();
Turbo[] turbo = Part.Where(x => x is Turbo).Cast<Turbo>().ToArray();

Turbo[0].name = "SportPiston"; 
Turbo[0].maxboostpressure = 5.0;

您将拥有 3 个已知类型的独立数组。现在您可以单独使用它们了。

请注意,索引不再像以前那样了。因此,如果您不想要这个,为什么不为它们创建单独的数组呢? ;)

请勿复制等...

var lst = new List<EngineParts>(); //fill it
foreach(var itm in lst.Where(x => x is Piston).Cast<Piston>())
{
    itm.maxboostpressure = 42;
}