Jonathan Wood
Jonathan Wood

Reputation: 67195

Any Way to Restrict the Types that a Type Variable may Hold?

I have code similar to the following. It associates integers with types. I want to then use this dictionary to look up the type for an given integer, and then instantiate that type.

Dictionary<int, Type> RegistrationMethods;

RegistrationMethods = new Dictionary<int, Type>();
RegistrationMethods.Add(1, typeof(RegistrationProvider_01));
RegistrationMethods.Add(2, typeof(RegistrationProvider_02));

Question: All of my types implement IRegistrationMethod. Is there any way to declare my dictionary so that it can only hold types that implement this interface? That would make my code more type safe.

Thanks for any tips.

Upvotes: 1

Views: 105

Answers (3)

You cannot enforce this restriction on a Type, and therefore neither on a Dictionary<…, Type>, but you could wrap such a dictionary in a specialized type:

class RestrictedTypeDictionary<TRestriction>
{
    public RestrictedTypeDictionary()
    {
        this.internalDictionary = new Dictionary<int, Type>();
    }

    private readonly Dictionary<int, Type> internalDictionary;

    public void Add(int key, Type value)
    {
        if (!typeof(TRestriction).IsAssignableFrom(value))  // <- that's the important bit
        {
            throw new ArgumentOutOfRangeException("value");
        }
        internalDictionary.Add(key, value);
    }

    public Type this[int key]
    {
        get
        {
            return internalDictionary[key];
        }
    }

    …
}

You could then use a RestrictedTypeDictionary<IRegistrationMethod> instead of a Dictionary<int, Type> to ensure the constraint that only Type values can be added that represent types deriving from IRegistrationMethod.

Concerning your bonus, given any type T with a default constructor, you can easily create an instance of that type using Activator.CreateInstance(typeof(T)).

Upvotes: 1

Selman Gen&#231;
Selman Gen&#231;

Reputation: 101681

All of my types implement IRegistrationMethod. Is there any way to declear my dictionary so that it can only hold types that implement this interface? That would make my code more type safe.

You can create a wrapper class for your Dictionary:

public class WrapperDictionary
{
    private Dictionary<int, Type> dictionary;

    public WrapperDictionary()
    {
        dictionary = new Dictionary<int, Type>();

    }

    public bool Add(int key, Type value)
    {
        if (!dictionary.ContainsKey(key) &&
            value.IsAssignableFrom(typeof (IRegistrationMethod)))
        {
            dictionary.Add(key, value);
            return true;
        }
        else return false;
    }

    public Type this[int key]
    {
        get
        {
            if (dictionary.ContainsKey(key)) return dictionary[key];
             /* throw exception or return null */
        }

    }
}

In order to create an instance of given type, you can use Activator.CreateInstance method:

var dict = new WrapperDictionary();

dict.Add(2, typeof(RegistrationProvider_01));

var type = dict[2];

var instance = Activator.CreateInstance(type);

Upvotes: 1

Lee
Lee

Reputation: 144136

If you just want to create them you could do:

Dictionary<int, Func<IRegistrationMethod>> RegistrationMethods;
RegistrationMethods.Add(1, () => new RegistrationProvider_01());

alternatively you could require all elements to be added through a method:

public void AddRegistrationMethod<T>(int i) where T : IRegistrationMethod, new()
{
    RegistrationMethods.Add(i, typeof(T));
}

Upvotes: 6

Related Questions