I have a class like the following:
public class DropDownControl<T, Key, Value> : BaseControl where Key: IComparable { private IEnumerable<T> mEnumerator; private Func<T, Key> mGetKey; private Func<T, Value> mGetValue; private Func<Key, bool> mIsKeyInCollection; public DropDownControl(string name, IEnumerable<T> enumerator, Func<T, Key> getKey, Func<T, Value> getValue, Func<Key, bool> isKeyInCollection) : base(name) { mEnumerator = enumerator; mGetKey = getKey; mGetValue = getValue; mIsKeyInCollection = isKeyInCollection; }
And I want to add a convenience function for Dictionaries (because they support all operations efficiently on their own).
But the problem is that such a constructor would only specify Key and Value but not T directly, but T is just KeyValuePair. Is there a way to tell the compiler for this constructor T is KeyValuePair, like:
public DropDownControl<KeyValuePair<Key, Value>>(string name, IDictionary<Key, Value> dict) { ... }
Currently I use a static Create function as workaround, but I would like a direct constructor better.
public static DropDownControl<KeyValuePair<DKey, DValue>, DKey, DValue> Create<DKey, DValue>(string name, IDictionary<DKey, DValue> dictionary) where DKey: IComparable { return new DropDownControl<KeyValuePair<DKey, DValue>, DKey, DValue>(name, dictionary, kvp => kvp.Key, kvp => kvp.Value, key => dictionary.ContainsKey(key)); }
No, basically. The static method in a non-generic class (such as DropDownControl [no <>]) is the best approach, as you should be able to use type-inference when you call Create() – i.e.
C# 3.0 helps here both via ‘var’ (very welcome here) and by the much-improved generic type inference rules. In some (more general) case, another similar option is an extension method, but an extension method to create a very specific control from a dictionary doesn’t feel very natural – I’d use a non-extension method.
Something like:
Another option is inheritance, but I don’t like it much…
This adds complexity and reduces your flexibility… I wouldn’t do this…
Overall, it sounds like you want to be working with just IDictionary<,> – I wonder if you can’t simplify your control to just use this, and force non-dictionary callers to wrap themselves in an IDictionary<,> facade?