Home > Mobile >  How can I return an array of different elements that inherit from the same class?
How can I return an array of different elements that inherit from the same class?

Time:04-19

I have a class A from which B and C inherit.
I have two lists: listB and listC, of the respective types.

I want to make a method that returns the two lists inside an array, like so:

public override List<A>[] GetAllItems()
{
    return new List<A>[2]
    {
        listB,
        listC
    };
}

However, when I try this approach, I get the following error, because I try to convert the inherited types incorrectly.

Cannot implicitly convert type 'System.Collections.Generic.List<Lae.B>' to 'System.Collections.Generic.List<Lae.A>' [Assembly-CSharp]csharp(CS0029)

Is there some way to create this array without converting the elements?


Note: I am not using a struct or class, because I want the array to be of various sizes based on logic above.

CodePudding user response:

public List<A>[] GetAllItems()
{
    var result = new List<A>[2] {
        listB.Cast<A>().ToList(),
        listC.Cast<A>().ToList(),
    };
    
    return result;
}

If you need to return array of Lists - easiest way is to use Cast linq extension method.

In reference to the comments you have to remember that if you modify listB or listC, the change won't be reflected in the casted collections.

Anyway, if you need to have an access to the original listB / listC collections references, you can use IEnumerable instead of List in order to not be forced to "materialize" the results. Example:

public IEnumerable<A>[] GetAllItems()
{
    return new IEnumerable<A>[] {
        listB,
        listC,
    };
}

Now when you access eg. allItems[0] it will reference to the original listB collection.

CodePudding user response:

You can't do that because instance of B is an also A but instance of List of B is not also List of A.

You should box the types in the collection, you can use Cast function of in the Linq namespace.

using System.Linq;

 List<A>[] GetAllItems()
   {
    var result = new List<A>[2] {
        listB.Cast<A>().ToList(),
        listC.Cast<A>().ToList(),
    };
    return result;
   }

Or you can do that manualy.

List<A>[] GetAllItems()
{
    var boxedListB = new List<A>();
    var boxedListC = new List<A>();
    foreach (var item in listB)
    {
        boxedListB.Add(item);
    }
    foreach (var item in listC)
    {
        boxedListC.Add(item);
    }
    var result = new List<A>[2] {
         boxedListB,
         boxedListC
     };

    return result;
}

Or you can use Select function in System.Linq namespace.

List<A>[] GetAllItems()
{

    var result = new List<A>[2] {
         listB.Select(x=> x as A).ToList(),
         listC.Select(x=>x as A).ToList()
     };

    return result;
}

You can check this document for more information about boxing/unboxing.

  • Related