是否有可能拥有不同结构体的List ?

本文关键字:List 结构体 有可能 拥有 是否 | 更新日期: 2023-09-27 18:02:24

我想做一个List,我可以把多个不同的结构。问题是我不能给List模板参数,因为结构没有公分母(并且结构的继承是不可能的)。我的意思是:

struct Apple
{
    float roundness;
    float appleness;
}
struct Orange
{
   float orangeness;
   bool isActuallyAMandarin;
}
List<???> fruitBasket;
void Main(string [] args)
{
    fruitBasket = new List<???>();
    fruitBasket.Add( new Apple());
    fruitBasket.Add( new Orange());
}

省略List的template参数,很明显,会导致错误:

Using the generic type 'System.Collections.Generic.List<T>' requires 1 type arguments

有办法做到这一点吗?也许与List或可能与数组或不同的集合类,不需要类型参数?

编辑:这个问题是关于结构体的,不是关于类的我完全意识到这个问题可以用类和继承来解决,但我只是不能自由地使用类来代替(第三方库问题…)。

是否有可能拥有不同结构体的List ?

有一个类是每个结构的基础:它是Object,所以你可以把它

  List<Object> fruitBasket;

,但它意味着封装列表中的每个结构。还有一种可能是

  List<ValueType> fruitBasket;

你可以在这里使用接口!

public interface IFruit {}
Apple : IFruit {...}
Orange : IFruit {...}
List<IFruit> list = new List<IFruit>();
list.Add(new Apple());
list.Add(new Orange());

但是,它仍然会导致装箱操作(接口是引用类型)

没问题。你只需要创建一个对象列表。你可以使用旧式的非泛型数组列表,就像我们在。net 1的早期所做的那样。x,或者一个泛型List。因为object是一切的根。

void Main(string [] args) {
  var fruitBasket = new List<Object>();
  fruitBasket.Add( new Apple());
  fruitBasket.Add( new Orange());
}

void Main(string [] args) {
  var fruitBasket = new ArrayList();
  fruitBasket.Add(new Apple());
  fruitBasket.Add(new Orange());
}

把东西从清单里拿出来是另一个问题,但是你没有问,是吗?

虽然你的问题已经得到了回答,我还是建议你去看看StackOverflow的这篇文章。这会让你明白很多事情。

在c#中,您可以使用接口来实现与值类型(结构)的多态性类似的东西,因为您不能直接从结构派生,但您可以使用多个结构类型实现特定的接口。

因此,您可以使用一个接口IFruits,而不是抽象结构Fruit

还没有提到的另一种可能性是定义一个结构,它包含足够的字段来封装任何所需结构可能包含的所有值,以及确定如何解释它们的方法。例如:

struct AppleOrOrange{浮动applenessOrOrangeness;int roundnessOrMandarinness;}

由于对float的任何操作都不会产生某些位模式,因此可以为橘子和非橘子保留两个位模式,并说如果roundnessOrMandarinness保持其中一个位模式,则该元素应被视为橘子;如果它保存另一个,则应将值按位转换为float,并将该元素视为苹果。请注意,在这种特殊情况下,这种方法将大大节省内存需求,而不是将所有内容打包(打包将使x86 [20 vs 8]的存储需求增加一倍以上,在x64 [32 vs 8]中的存储需求增加四倍)。

如果大多数项目都很简单,但有一些复杂的项目,那么另一种方法是使用一个结构体,其中包含"简单"项目的数据以及用于补充信息的引用类型。例如,如果有一个绘图操作列表,最常见的是"moveto"或"lineto",每个操作只需要一个xy,但有些操作需要更多的信息,可以定义一个struct:

structure DrawListEntry {public int X,Y; public DrawOperation Op;}

对于movetolineto表项,op将保存对单例的引用;对于像ShowBitmap这样的条目,它可以保存对封装任意附加信息的非单例对象的引用。如果90%的绘制条目是"移动的"或"行向的",这种方法将需要12或16字节,而不是24或32]。将大多数条目的存储成本削减一半将是一个巨大的胜利。此外,var it=myList[index]; it.Op.Draw(it.X, it.Y)的缓存性能(it.Op在90%的情况下识别两个单例之一)可能比在完全独立的对象实例上调用it.Draw()要好。

如果struct不是您唯一的选择,您应该尝试使用继承:

abstract class Fruit {
}
class Apple : Fruit {
}
class Orange : Fruit {
}
List<Fruit> fruits = new List<Fruit>();
fruits.Add(new Apple());