- You can't constrain a specific variable. It only works on classes and methods. It really doesn't make any sense in the variable level, to be honest.
- What you want is a custom class -
class WeirdDictionary : IDictionary<Type, IEnumerable>
, that will overload the Add method to take a Type and an IEnumerable of that type, which you can do using constraints, and cast the IEnumerable<> to IEnumerable. Overload the indexer aswell, and cast it back to the relevant type.
All this casting is needed, since generics are strict about IEnumerable<Base>
being as good as IEnumerable<Derived>
(This is called variance, I believe?)
This solution is slightly generalized, since reuse rocks
Edit by 280Z28:
At first I marked this down because point #2 was confusing and I misinterpreted it. By using explicit implementation of methods in IDictionary<Type, IEnumerable>
and providing generic alternatives, you can get a pretty clean interface. Note that you cannot create generic indexers, so you'll have to always use TryGet<T>
(which is a good idea anyway). I only included explicit implementation of one of the IDictionary<>
methods to show how to perform the checks. Do not derive WeirdDictionary
directly from Dictionary<Type, IEnumerable>
or you will lose the ability to guarantee constraints in the underlying data.
class WeirdDictionary : IDictionary<Type, IEnumerable>
{
private readonly Dictionary<Type, IEnumerable> _data =
new Dictionary<Type, IEnumerable>();
public void Add<T>(IEnumerable<T> value)
{
_data.Add(typeof(T), value);
}
public bool TryGet<T>(out IEnumerable<T> value)
{
IEnumerable enumerable;
if (_data.TryGetValue(typeof(T), out enumerable)
{
value = (IEnumerable<T>)enumerable;
return true;
}
value = null;
return false;
}
// use explicit implementation to discourage use of this method since
// the manual type checking is much slower that the generic version above
void IDictionary<Type, IEnumerable>.Add(Type key, IEnumerable value)
{
if (key == null)
throw new ArgumentNullException("key");
if (value != null && !typeof(IEnumerable<>).MakeGenericType(key).IsAssignableFrom(value.GetType()))
throw new ArgumentException(string.Format("'value' does not implement IEnumerable<{0}>", key));
_data.Add(key, value);
}
}
End 280Z28