user3573634
user3573634

Reputation: 45

Generic Method for List of Generic Classes

I have problem. For example, considering these 4 classes.

public abstract ParentContainer<T> where T: Parentfoo
{
    public List<T> fooList; 
}

//Let there be many different ChildContainers with different types.
public class ChildContainer : ParentContainer<ChildFoo>
{
}

public abstract class ParentFoo
{
    public string name; 
}

public class ChildFoo : ParentFoo
{
}

How can I write a method which accepts a List of any arbitrary ChildContainers as a parameter, which do operation on their fooLists? Is it even possible?

Additional Explanation, there are many different childs of ParentContainer, each with a List of a different child of foo.

public class ChildContainerB : ParentContainer<ChildFooB>{}
public class ChildContainerC : ParentCOntainer<ChildFooC>{}
...

public class ChildFooB : ParentFoo;
public class ChildFooC : ParentFoo;

Then I need a method something like this

//X means it can be any arbitrary ChildContainer
public void method(List<ChilContainerX> list) 
{
    foreach(ChildContainerX x in list)
    {
        print(x.fooList.Last().name);
    }
}

Upvotes: 1

Views: 83

Answers (3)

Unni Krishnan
Unni Krishnan

Reputation: 94

class Program
{
    static void Main(string[] args)
    {

        List<ParentContainer<ChildFoo>> ca = new List<ParentContainer<ChildFoo>>();

        ProcessContainers processor = new ProcessContainers();

        ca.Add(new ChildContainerA { fooList = new List<ChildFoo>() });
        ca.Add(new ChildContainerA { fooList = new List<ChildFoo>() });
        ca.Add(new ChildContainerA { fooList = new List<ChildFoo>() });
        ca.Add(new ChildContainerB { fooList = new List<ChildFoo>() });

        processor.Process(ca);
    }
}


public abstract class ParentContainer<T> where T: ParentFoo
{
    public List<T> fooList;
}

//Let there be many different ChildContainers with different types.
public class ChildContainerA : ParentContainer<ChildFoo>
{
}
public class ChildContainerB : ParentContainer<ChildFoo>
{
}

public class ProcessContainers
{
    public void Process<T>(List<ParentContainer<T>> childContainers) where T : ParentFoo
    {
        foreach(var item in childContainers)
        {
            foreach(var foo in item.fooList)
            {
                foo.Porcess();
            }
        }
    }
}

public abstract class ParentFoo
{
    public string name;

    public abstract void Porcess();
}

public class ChildFoo : ParentFoo
{
    public override void Porcess()
    {
        //Do some processing
    }
}

Upvotes: 0

War
War

Reputation: 8628

Unless I misunderstand the question, you want something like this ...

public void DoStuffWith<T>(List<ParentContainer<T>> containers) where T : Parentfoo
{
     //TODO: implement
}

This would work on objects of type ...

List<ParentContainer<ParentFoo>>
List<ParentContainer<ChildFoo>>

where ChildFoo : ParentFoo

and solves the issue of "List<ParentContainer<ParentFoo>> does not implement IEnumerable<ParentContainer<ChuldFoo>>" which I suspect is the compiler you are seeing.

Taking this a step further something like ....

public void DoStuffWith<ContainerT,ElementT>(List<ContainerT<ElementT>> containers) 
  where ContainerT : ParentContainer 
  where ElementT : Parentfoo
{
     //TODO: implement
}

... likely over complicates the issue but i suspect is what you are trying to achieve.

At this point I would question the data structures you have and give them some common parent for example ...

public class ParentContainer<T> : IEnumerable<T> { ... }
public class ChildContainer<T> : ParentContainer<T>, IEnumerable<T> { ... } 

Since both implement IEnumerable you can now do ...

public void DoStuffWith<T>(IEnumerable<T> containers) where T : ParentFoo
{
     //TODO: implement
}

This avoids the need to be concerned with the collection type at all.

Upvotes: 0

DavidG
DavidG

Reputation: 119156

So what you are asking isn't possible because you need a concrete type for the List<>. There are a couple of workarounds though.

  1. Use List<object>. This is obviously not great because as it means you lose type checking completely and could end up with anything being added to the list. So for that reason, I wouldn't recommend this approach.

  2. Make ParentContainer<> implement a marker interface. For example:

    public interface IParentContainer
    {
    }
    
    public abstract class ParentContainer<T> : IParentContainer
        where T: ParentFoo
    {
        //snip
    }
    

    And now you can have your list like this:

    var containers = new List<IParentContainer>
    {
        new ChildContainer(),
        new ChildContainer2()
    };
    

Upvotes: 1

Related Questions