Question

I would like to make a a List in which I can put multiple different structs. The problem is that I can't give the List the template argument, as the struct have no common denominator (and inheritance of structs isn't possible). I mean something of the following:

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());
}

Leaving out the List's template argument gives, for obvious reasons, the error:

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

Is there a way of doing this? Perhaps with a List or perhaps with an array or different collection class that doesn't require the type argument?

Edit: This question is specifically about structs, not about classes. I am fully aware of the fact this could be solved with classes and inheritance, but I am simply not at the liberty to use classes instead (3rd party library issues...).

Was it helpful?

Solution

There's one class that's base for each structure: it's Object, so you can put it

  List<Object> fruitBasket;

but it means boxing each structure in the list. Yet another possibility is

  List<ValueType> fruitBasket;

OTHER TIPS

you can make use of interfaces here!

public interface IFruit {}

Apple : IFruit {...}

Orange : IFruit {...}

List<IFruit> list = new List<IFruit>();
list.Add(new Apple());
list.Add(new Orange());

Though, it would still cause boxing operation (interface being reference type)

No problem. You just make a List of Object. You can either use an old-fashioned non-generic ArrayList, the way we did back in the olden days of .Net 1.x, or a generic List. It works because object is the root of everything.

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

or

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

Getting things out of the list is another problem, but you didn't ask that, did you?

Although your question has been answered, i'll suggest you to also go through THIS post of StackOverflow. It's going to make you clear about lots of stuff.

In C#, you can use interfaces to achieve something akin to polymorphism with value types (structs) as you can't derive directly from a struct but you can have multiple struct types implement specific interfaces.

Therefore, instead of your abstract struct, Fruit, you can have an interface, IFruits.

Another possibility not yet mentioned is to define a structure which contains enough fields to encapsulate all the values that any of the desired structures could hold, as well as a means of determining how they should be interpreted. For example:

struct AppleOrOrange { float applenessOrOrangeness; int roundnessOrMandarinness; }

Since there are certain bit patterns which will never be yielded by any operations on float, one could reserve two bit patterns for mandarin and non-mandarin oranges, and say that if roundnessOrMandarinness holds one of those bit patterns the element should be regarded as an orange; it holds the other, the value should be bitwise-converted to a float and the element regarded as an apple. Note that in this particular case, this approach will save considerably on memory requirements versus boxing everything (boxing would more than double storage requirements in x86 [20 vs 8], and quadruple them in x64 [32 vs 8]).

An alternative approach if the majority of items are simple but there are a few complicated ones, would be to use a struct which contains the data for a "simple" item along with a reference type for supplemental information. For example, if one has a list of drawing operations and the most common ones are "moveto" or "lineto", each of which just needs an x and a y, but some operations require more information, one could define a struct:

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

For moveto and lineto entries, op would hold a reference to a singleton; for entries like ShowBitmap, it could hold a reference to a non-singleton object encapsulating arbitrary additional information. If 90% of drawing entries are "moveto" or "lineto", this approach would require 12 or 16 bytes each for those rather than 24 or 32]. Cutting by half the storage cost of the majority of entries would be a big win. Further, the cache performance of var it=myList[index]; it.Op.Draw(it.X, it.Y), with it.Op identifying one of two singletons 90% of the time, may be better than calling it.Draw() on entirely-independent object instances.

You should try and use inheritance if struct is not one and only option for you:

abstract class Fruit {
}

class Apple : Fruit {
}

class Orange : Fruit {
}

List<Fruit> fruits = new List<Fruit>();
fruits.Add(new Apple());

and etc

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top