Frank Lioty
Frank Lioty

Reputation: 977

Unified way to access arrays with different types

Supposing I have the following classes:

class Master {
  int x;
  int y;

  public int X { get { return x; } set { x = value; } }
  public int Y { get { return y; } set { y = value; } }
}

class Sub1:Master {
  int z;

  public int Z { get { return z; } set { z = value; } }
}

class Sub2:Master {
  int w;

  public int W { get { return w; } set { w = value; } }
}
class Sub3:Master {
  int t;

  public int T { get { return t; } set { t = value; } }
}

Then I have defined three different arrays, one for each Sub* type:

List<Sub1> array1;
List<Sub2> array2;
List<Sub3> array3;

And finally I need a way to access all instances in a unified way. The idea was to use a new array List<T>[] array4 = new[] {array1, array2, array3}; and use an int as index, so I don't have to write three times the common operations for properties X and Y.

However, I can't do it in this way because the three arrays have different type. What can I use?

Upvotes: 0

Views: 221

Answers (3)

Jonathan Rupp
Jonathan Rupp

Reputation: 15762

You can actually make this work by using the fact that IEnumerable<T> is declared as IEnumerable<out T>, and that Enumerable.ElementAt<T> is optimized for the runtime type of the IEnumerable<T> implementing IList<T>. That lets you do this:

var x = new IEnumerable<Master>[] {array1, array2, array3};
x[0].ElementAt(4);

While still getting constant-time access to the individual elements of the lists. It feels a little clunky, but should still work.

If it fits the work being done, a better option in my opinion would be to create a generic method, and call the generic method on each of your lists:

private void MainMethod()
{
    List<Sub1> array1 = new List<Sub1>();
    List<Sub2> array2 = new List<Sub2>();
    List<Sub3> array3 = new List<Sub3>();
    DoOperation(array1);
    DoOperation(array2);
    DoOperation(array3);
}

private void DoOperation<T>(List<T> list) where T: Master
{
    // do work here
    list[0].X = 0;
}

Upvotes: 0

Jo&#227;o Angelo
Jo&#227;o Angelo

Reputation: 57658

They share a base type so you can create a List<Master> to hold instances of all three types.

Ultimately, all objects share the same base type object so it always possible to have a List<object>, but in this case they share a base type higher in the hierarchy so you can use Master.

To create a list for all the instances you can do something like this:

var all = new List<Master>(array1.Count + array2.Count + array3.Count);

all.AddRange(array1);
all.AddRange(array2);
all.AddRange(array3);

First you create a new list and since you already know what the expected capacity should be you use the constructor overload that accepts an int capacity. This way the list does not have to be resized when you add the other collections, which leads to more efficient code.

As a side note and I know this is probably only sample code but nonetheless you should name your variables according to what they represent, so naming something like array* should be reserved for when they really represent arrays.

Upvotes: 1

Edgar Hernandez
Edgar Hernandez

Reputation: 4030

List implements the non-generic interfaces ICollection, IEnumerable and IList, so you can create a new array of IList[] array4 = { array1, array2, array3 };

Or, while adding elements at your Lists you could add them (also) to another list of type Master, like this

List<Sub1> array1 = new List<Sub1>();
List<Sub2> array2 = new List<Sub2>();
List<Sub3> array3 = new List<Sub3>();
List<Master> array4 = new List<Master>();

...

public void AddSub1(Sub1 sub)
{
    array1.Add(sub);
    array4.Add(sub);
}

public void AddSub2(Sub2 sub)
{
    array2.Add(sub);
    array4.Add(sub);
}

public void AddSub3(Sub3 sub)
{
    array3.Add(sub);
    array4.Add(sub);
}

This way, you can iterate over all elements of array4:

foreach(Master master in array4)
{
   master.DoSomething();
}

Upvotes: 0

Related Questions