Reputation: 1512
I'm trying to store types in a collection, so that i can later instantiate objects of the types in the collection. But I'm not sure how to do this the best way.
What i have so far:
List<Type> list = new List<Type>();
list.Add(typeof(MyClass));
var obj = (MyClass)Activator.CreateInstance(list[0]);
I would like to have some constrains on the Type
, or better yet, just a generic type in the collection instead of an instantiated Type
object. Is this possible?
Upvotes: 3
Views: 4340
Reputation: 3783
Jon,
If you are using CodeContracts, you could require a number of known types. The code analysis would flag any calls to your collection with invalid types.
public class TypeCollection : List<Type>
{
public TypeCollection()
{
}
public new void Add(Type type)
{
Contract.Requires(type == typeof(string) || type == typeof(Stream));
base.Add(type);
}
}
public class TestCollection
{
public void Test()
{
TypeCollection collection = new TypeCollection();
// This gets compile time warning:
collection.Add(typeof(int));
}
}
But, if you know the types in advance, it might make more sense to specify them all in an enum and create a collection of valid enums for the type creation you want to support.
Upvotes: 1
Reputation: 3561
In this particular scenario, where it seems we have a "factory" pattern, we would constrain the method invoking the activator, such as
private readonly List<Type> _supportedTypes = new List<Type> ();
public void RegisterSupportedType<T> () where T : SomeConstraintType
{
_supportedTypes.Add (typeof (T));
}
// if we do not know the type, but somehow know an index to type
public object Create (int supportedTypeIndex)
{
object untyped = Activator.
CreateInstance (_supportedTypes[supportedTypeIndex]);
return untyped;
}
// if we know instance type\subtype (eg interface) and know an index
public T Create<T> (int supportedTypeIndex)
{
T typed = default (T);
object untyped = Create (supportedTypeIndex);
if (!(untyped is T))
{
// throw meaningful exception :)
}
typed = (T)(untyped);
return typed;
}
An alternative, is to create a constrained Type
public class ConstrainedType<T>
{
public Type Type { get; private set; }
public ConstrainedType (Type type)
{
// may have this backward, would have to fact check before
// rolling out to prod ;)
if (!typeof (T).IsAssignableFrom (type))
{
// throw meaningful exception!
}
Type = type;
}
}
List<ConstrainedType<SomeTypeConstraint>> list =
new List<ConstrainedType<SomeTypeConstraint>> ();
// will throw meaningful exception if MyClass is not
// SomeTypeConstraint or a sub class
list.Add (new ConstrainedType (typeof (MyClass)));
SomeTypeConstraint baseType =
(SomeTypeConstraint)(Activator.CreateInstance(list[0].Type));
Upvotes: 4
Reputation: 12993
If you were to implement your own collection, you could use generic type constraints:
public class MyList<T>
where T : IMyConstraint
Upvotes: 0
Reputation: 131796
That's not how generic collection constraints work.
Generic constraints restrict which types are legal for instantiating a generic type. There are several different kinds of constraints, but the common ones limit a generic parameter to either inherit or be an instance of a given type, or be a type that implements a particular interface (or set of interfaces).
Type
, on the other hand, is a class that describes information about a type in your application or one of it's libraries. Specific kinds of types don't inherit or extend Type
- rather there is a different instance of Type
for each type available. You cannot use generic constraints to control which instances of Type
may be added to your collection.
Without more detail about how you want to "constrain" the information in the collection, it's hard to say what route you should take. For example, if all you want to do is ensure that only unique types (no dups) are stored, that can be achieved with a HashSet (rather than a list). But if you want something more specialized - like limiting the Type
instances that can be added to some subset of types, then you will likely need to implement your own collection, and implement gaurd logic in the Add/Insert methods.
Upvotes: 5
Reputation: 1734
first way(seems stupid but it is safe):
(create a wrapper over the List || implement IList) and check .Exists(item) in the .Add Method.
Upvotes: 0