Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Storing a list of different generic types in a class

Tags:

Class structure

I've attached a picture of what I'm trying to do. Let's say I have a list of T in a class

public class MyClass<T>      where T : IMyInterface {     public List<T> list = new List<T>; } 

Now, another class has a list of MyClass.

public class AnotherClass {     public List<MyClass<IMyInterface>> list = new List<MyClass<IMyInterface>>; } 

What is the T that I should put for MyClass? If I put T, then it assumes all types in that class are the same, but it isn't. If I put IMyInterface, I couldn't cast IMyInterface to T when accessing these classes.

new AnotherClass().list.Add(new MyClass<T>());  

What is the type here right now? The list in AnotherClass generic type is IMyInterface but the thing I want to add in is T, which T I want to be dynamic but they are still under IMyInterface.

like image 769
Lee Song Avatar asked Apr 07 '16 06:04

Lee Song


People also ask

Can we store different data types in list in C#?

We can use an ArrayList class that is present in the System. Collections namespace,. Using it we can store different types because the ArrayList class operates on the object type.

Is list a generic collection?

Generic List<T> is a generic collection in C#. The size can be dynamically increased using List, unlike Arrays.

Is list a generic type?

Remarks. The List<T> class is the generic equivalent of the ArrayList class.


2 Answers

The T in a generic must be the same through out its lifetime.

for an example

var a = new MyClass<int>(); a.list.Add(1); //since a's generic T is declared as int the list is now also int  var b = new MyClass<string>() b.list.Add("string"); //in b its now declared as a string and avccepts only string 

So when you are doing this.

var c = new MyClass<IMyInterface>(); c.list.Add(ObjectImplementingIMyInterface); //You must add something that implements IMyInterface 

The only thing you know about the content is that it implements IMyInterface now if you want to split the execution of the object then you must check the type of the object via reflection.

if(c.list[i].GetType() == typeof(ClassA_IMyInterface) {     //Execute on ClassA_IMyInterface     //If you are after the ClassA      //and want to run something speciffic for it the cast     ClassA clA = = (ClassA)c.list[i];     //Now you have access to the implementation of ClassA instead of just the interface  } else if (c.list[i].GetType() == typeof(ClassB_IMyInterface) {     //Execute on ClassB_IMyInterface } 

Here is an example i made in ConsoleApplication showing how it lays out.

public class MyClass<T> where T : IMyInterface {     public List<T> list = new List<T>(); } public interface IMyInterface { } public class Foo : IMyInterface { } public class Bar : IMyInterface { } public class FooBar {     public void Test()     {         var content = new MyClass<IMyInterface>();         content.list.Add(new Foo());         if (content.list[0] is Foo)         {             //Execute on Foo              var g = (Foo)content.list[0];             //Now you can access Foo's methods and not only the Interfaces             Console.WriteLine("Foo");         }         else if (content.list[0] is Bar)         {             //Execute on Bar             var g = (Bar)content.list[0];             //Now you can access Bar's methods and not only the Interfaces             Console.WriteLine("Bar");         }     } } 
like image 161
Thomas Andreè Wang Avatar answered Sep 23 '22 10:09

Thomas Andreè Wang


I think your issue is that you do not need to use generics for this. If you specify your class as:

public class MyClass {     public IList<IMyInterface> list = new List<IMyImterface>(); } 

Then you can add to this any instance of any class implementing the interface.

public class DummyClass : IMyInterface {}  public class AnotherClass { {     IList<MyClass> anotherList = new List<MyClass>();      public void AMethod()     {         MyClass myList = new MyClass();         myList.Add(new DummyClass());          anotherList.Add(myList);     } } 

Then you can access all items from the list as IMyInterface directly, or if you want items of a specific class, you can use LINQ:

foreach (IMyImterface item in myList.Where(x => x is DummyClass)) {     DummyClass dummy = (DummyClass)item; }  // or foreach (IMyImterface item in myList.OfType<DummyClass>()) {     DummyClass dummy = (DummyClass)item; } 

Or you can just try casting and check if null:

foreach (IMyIntetface item in myList) {     DummyClass dummy = item as DummyClass;     if (dummy != null)     {         // do something     } } 
like image 30
Steve Harris Avatar answered Sep 21 '22 10:09

Steve Harris