Nicolas Voron
Nicolas Voron

Reputation: 2996

Generic types, collections and object reference

I have a generic type GenericClass<Type_T> (Type_T implements IType_T if it helps). I create some instances of it, for example GenericClass<Type1>, GenericClass<Type2>.

No I want an index over a bunch of theses class instances. I first thought about a dictionary : Dictionary<int, GenericClass<Type1>> which obviously doesn't work.

Is there a known solution to this problem ? How to store an indexed collection of generic types ?

Upvotes: 4

Views: 139

Answers (4)

Fabian
Fabian

Reputation: 2086

You can also look at covariance in generics.

You also need to define a common interface for GenericClass but it can be generic:

interface IType { }
interface IGenericClass<out T> where T : IType { }
class Type1 : IType { }
class Type2 : IType { }
class GenericClass<T> : IGenericClass<T> where T : IType { }

class Program
{
    static void Main(string[] args)
    {
         Dictionary<int, IGenericClass<IType>> dict = new Dictionary<int, IGenericClass<IType>>();
                dict[0] = new GenericClass<Type2>();
                dict[1] = new GenericClass<Type1>();
     }
}

But it won't allow:

 Dictionary<int, IGenericClass<object>> dict = new Dictionary<int, IGenericClass<object>>();

Edit: For completeness

You can't use this to pass IType as parameter in IGenericClass. It requires contravariance and using contravariance will break the assignment to Dictionary<int, IGenericClass<IType>> dict:

A covariant type parameter is marked with the out keyword (Out keyword in Visual Basic, + for the MSIL Assembler). You can use a covariant type parameter as the return value of a method that belongs to an interface, or as the return type of a delegate. You cannot use a covariant type parameter as a generic type constraint for interface methods.

 interface IGenericClass<out T> where T : IType
 {
    T GetType(); //possible
    void SetType(T t); //not possible
 }

Upvotes: 2

Mohit S
Mohit S

Reputation: 14044

Almost similar with an answer by Hjalmar Z but the change is instead of List I have used ObservableCollection. Which probably would serve the problem of indexed collection

interface IType { }
interface IGenericClass { }
class Type1 : IType { }
class Type2 : IType { }
class GenericClass<T> : IGenericClass where T : IType { }

class Program
{
    static void Main(string[] args)
    {
        var gen1 = new GenericClass<Type1>();
        var gen2 = new GenericClass<Type2>();
        ObservableCollection<IGenericClass> GCClass = new ObservableCollection<IGenericClass>();
        GCClass.Add(gen1);
        GCClass.Add(gen2);
    }
}

Upvotes: 1

xanatos
xanatos

Reputation: 111850

Normally what you do in this case is create a common non-generic base class (sometimes an abstract class, or a non-generic interface), GenericClass, from which GenericClass<Type_T> derives, and that contains the methods that don't have as a parameter/return type the Type_T. You use this base class/interface exactly for what you wrote: Dictionary<int, GenericClass>...

A race-to-the-bottom is: Dictionary<int, object>, because object is the base class for all the class types in .NET.

Classical case: List<T> derives from IList, ICollection, IEnumerable.

Upvotes: 6

Hjalmar Z
Hjalmar Z

Reputation: 1601

A compact code example following up on xanatos' answer:

interface IType { }
interface IGenericClass { }
class Type1 : IType { }
class Type2 : IType { }
class GenericClass<T> : IGenericClass where T : IType { }

class Program
{
    static void Main(string[] args)
    {
        var gen1 = new GenericClass<Type1>();
        var gen2 = new GenericClass<Type2>();
        var list = new List<IGenericClass>();
        list.Add(gen1);
        list.Add(gen2);
    }
}

Upvotes: 3

Related Questions