Collection of common types

If I have a general class:

public class MyClass<T> { public T Value; } 

I want to create some elements, such as ...

 new MyClass<string> new MyClass<int> 

... and add them to the collection. How to define a collection so that it can contain a list of common types? Then I want to iterate through the collection and use the Value property. Possible?

+24
source share
9 answers

Ask your common class to inherit from a non-generic base or implement a non-generic interface. Then you can have a collection of this type and use any code that you use to access the contents of the collection.

Here is an example.

 public abstract class MyClass { public abstract Type Type { get; } } public class MyClass<T> : MyClass { public override Type Type { get { return typeof(T); } } public T Value { get; set; } } // VERY basic illustration of how you might construct a collection // of MyClass<T> objects. public class MyClassCollection { private Dictionary<Type, MyClass> _dictionary; public MyClassCollection() { _dictionary = new Dictionary<Type, MyClass>(); } public void Put<T>(MyClass<T> item) { _dictionary[typeof(T)] = item; } public MyClass<T> Get<T>() { return _dictionary[typeof(T)] as MyClass<T>; } } 
+24
source

The only way I can think of from the top of my head is to do the following (completed in the Console app for testing):

 class Program { static void Main(string[] args) { var x = new MyClass<string>() { Value = "34" }; var y = new MyClass<int>() { Value = 3 }; var list = new List<IMyClass>(); list.Add(x); list.Add(y); foreach (var item in list) { Console.WriteLine(item.GetValue); } } private interface IMyClass { object GetValue { get; } } private class MyClass<T> : IMyClass { public T Value; public object GetValue { get { return Value; } } } } 

i.e. Let MyClass implement an empty interface, and then create your collections as those that contain instances of classes that implement this interface.

Update: I added the "GetValue" method to the interface, which allows you to access the "Value" of the MyClass instance as an object. This is about as good as afaik would like if you want to have a collection that contains mixed types.

+7
source

You want to define a base class for MyClass, then your collections will be a list of the base class. Example:

 void Main() { var a = new MyClass<string>(); var b = new MyClass<int>(); var c = new List<MyBase>(); c.Add(a); c.Add(b); } public class MyBase { } // Define other methods and classes here public class MyClass<T> : MyBase { public T Value { get; set;} } 
+3
source

You want to have a MyClass collection for which the value of a parameter of type T is different in each instance. This is not possible in .NET; it lacks the equivalent of a Java template (?). Instead, you need to create a non-generic base class or interface that MyClass can implement. For example:

 public interface IMyClass { object Value { get; set; } } public class MyClass<T> : IMyClass { public T Value { get; set; } object IMyClass.Value { get { return Value; } set { Value = (T)value; } } } List<IMyClass> m = new List<IMyClass> { new MyClass<string>(), new MyClass<int> }; 
+3
source

I have interfaces for most of my common types with "Untyped" members:

 private interface IMyClass { object UntypedValue { get; } } private class MyClass<T> : IMyClass { T Value { get; set; } object UntypedValue { get { return Value; } } } 

You can also do this using an explicit implementation of the interface, but in my opinion it is much easier with a separate name. (There are also CA recommendations for explicit interface implementation)

+3
source

I think the problem here is that the common classes are really not the same. These are just templates that create all new types at compile time (if I understand correctly). Therefore, MyClass<int> and MyClass<string> are completely different types, depending on runtime. They can also be MyIntClass and MyStringClass , which you obviously cannot have on the same list, not boxing in the first place. They do not (necessarily) inherit the same base class, implement the same interfaces or something else. They are as different as any other two types, and you should treat them as such (although you think you know better).

Of course, you can implement their interface, inherit the base object or any of the other parameters that are already set. See commongenius answer for a good way to do this.

+2
source

I believe that your collection will have one MyClass type (since T must be the same), because the compiler will not know what types you added to which elements in the collection.

In other words, if you must add 2 items to the list:

 list.Add(new MyClass<string>()); list.Add(new MyClass<int>()); 

then try to reference one:

 var myItem = list[1]; 

The compiler does not know which generic name was assigned to the MyClass list in element 1 , because the elements are added at run time, but the generics are determined at compile time.

I am sure that what you want to do cannot be done.


If you know in advance the number of elements, maybe you can use Tuple ?

+1
source

IList

It is not possible to define a general collection that can accept any taste of your general class ... i.e. IList<MyClass> . Generic classes are just a short shorthand for the developer to save on writing a bunch of repetitive code, but during compilation every taste of the generic class is translated into a specific one. those. if you have MyClass<string> , MyClass<int> , MyClass<bool> , then the compiler will generate 3 separate and different classes. The only way to do what you want is to have an interface for your common.

 public interface IMyGeneric { Type MyType { get; set;} } class MyGeneric<T> : IMyGeneric { public MyGeneric() { MyType = typeof(T); } public Type MyType { get; set; } } 

and then you can say

 IList<IMyGeneric> list = new List<IMyGeneric>(); list.add(new MyGeneric<string>()); list.add(new MyGeneric<int>()); 
+1
source

Since .Net 3 was a CompositeCollection class that allows you to contain several unique elements or even collections. It is used by WPF developers to store and display various elements in Xaml. But this does not mean that it cannot be used in situations other than WPF.

Here is an example where I store different things from strings to decimals and extract and list all elements, and then elements of a certain type:

 CompositeCollection cc = new CompositeCollection(); cc.Add(1); cc.Add("Item One"); cc.Add(1.0M); cc.Add(1.0); cc.Add("Done"); Console.WriteLine ("Every Item"); foreach (var element in cc) Console.WriteLine ("\t" + element.ToString()); Console.WriteLine (Environment.NewLine + "Just Strings"); foreach (var str in cc.OfType<string>()) Console.WriteLine ("\t" + str); /* Outputs: Every Item 1 Item One 1.0 1 Done Just Strings Item One Done */ 
+1
source

All Articles