Reputation: 2996
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
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
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
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
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