Reputation: 13716
Say that I have a series of classes:
abstract class MyClass { }
class MyFirstClass : MyClass { }
class MySecondClass : MyClass { }
class MyThirdClass : MyClass { }
I want to do something based on a configurable list of these derived class types, so I want to store the chosen class's Type
s in a list. I know I could create a List<Type>
, but I could theoretically add any class to that list. On the other hand, a List<MyClass>
would be a list of instances of these classes, rather than a list of the types themselves. I could also create an enum
with one value that corresponds to each derived type, and have a factory method to create the correct one as needed, but that's at least two more places I'd have to update when I added MyFourthClass
.
Is there a way to do something like new List<typeof(MyClass)>() = new[] { typeof(MyFirstClass), typeof(MyThirdClass)}
? Does the very fact I'm asking this question imply a problem with my design?
Upvotes: 1
Views: 811
Reputation: 16598
There's no way to do this with static, compile-time type checking. Your best bet is to go with a solution like Raul Otaño's in which you do your checks at runtime.
Why can't you do this? The reason is that C# lacks static metaclass types. A metaclass is the class of a class. In other words, the instances of a metaclass are themselves classes. If C# had metaclasses, you could say something like IList<MyClassMeta>
(or perhaps the syntax would be IList<meta MyClass>
and the compiler would only allow you to pass MyClass (or its subclasses) as "instances", e.g.,
IList<meta MyClass> list;
list.Add(MyClass);
I've been wanting this functionality for a long time, but I don't expect it any time soon.
Upvotes: 1
Reputation: 4770
What you want is a generic list of types (List<Type>
) but like you said, you can insert any type there. The solution I can give you is to implement your own List of types from MyClass, for instance:
class TypeMyClassList : IList<Type>
{
private readonly List<Type> _list = new List<Type>();
private bool CheckType(Type type)
{
return type.IsSubclassOf(typeof (MyClass)) || typeof (MyClass) == type;
}
public IEnumerator<Type> GetEnumerator()
{
return _list.GetEnumerator();
}
IEnumerator IEnumerable.GetEnumerator()
{
return GetEnumerator();
}
public void Add(Type item)
{
if (CheckType(item))
_list.Add(item);
else
throw new InvalidOperationException("You can't add other types than derived from A");
}
public void Clear()
{
_list.Clear();
}
public bool Contains(Type item)
{
return _list.Contains(item);
}
public void CopyTo(Type[] array, int arrayIndex)
{
_list.CopyTo(array, arrayIndex);
}
public bool Remove(Type item)
{
return _list.Remove(item);
}
public int Count
{
get { return _list.Count; }
}
public bool IsReadOnly { get { return false; } }
public int IndexOf(Type item)
{
return _list.IndexOf(item);
}
public void Insert(int index, Type item)
{
if (!CheckType(item))
throw new InvalidOperationException("You can't insert other types than derived from A");
_list.Add(item);
}
public void RemoveAt(int index)
{
_list.RemoveAt(index);
}
public Type this[int index]
{
get
{
return _list[index];
}
set
{
Insert(index, value);
}
}
}
Then you could do thinks like this that you want:
var typeMyClassList = new TypeMyClassList
{
typeof(MyClass),
typeof(MyClassA),
typeof(MyClassB)
};
The bad thing is that it will allows to do this in compilance time (the error will be raised on runtime):
var typeMyClassList = new TypeMyClassList
{
typeof(MyClass),
typeof(MyClassA),
typeof(MyClassB),
typeof(string)
};
Upvotes: 3