I want to mimic the Python collections.defaultdict in C#. The following works fine as long as the value type has a parameterless constructor:
public class DefaultDictionary<TKey, TValue> : Dictionary<TKey, TValue> where TValue : new()
{
public new TValue this[TKey key]
{
get
{
TValue val;
if (!TryGetValue(key, out val)) {
val = new TValue();
Add(key, val);
}
return val;
}
set { base[key] = value; }
}
}
But what if I want to use a constructor that takes the key as argument? Or generally, a factory function that, given the key, returns an instance of the value type?
public class DefaultDictionary<TKey, TValue> : Dictionary<TKey, TValue> where TValue : new()
{
private readonly Func<TKey, TValue> factory;
public DefaultDictionary() : this(key => new TValue())
{}
public DefaultDictionary(Func<TKey, TValue> factory)
{
this.factory = factory;
}
public new TValue this[TKey key]
{
get
{
TValue val;
if (!TryGetValue(key, out val)) {
val = factory(key);
Add(key, val);
}
return val;
}
set { base[key] = value; }
}
}
Now the problem is that TValue is still required to have a parameterless constructor, even when a factory function is used. The following won't compile if Thingy does not have a parameterless constructor:
new DefaultDictionary<int, Thingy>(key => new Thingy(key, otherStuff, moreStuff));
However, removing the constraint will cause error CS0304 in the new TValue() statement.
Intuitively I would want to place the type constraint on the DefaultDictionary() constructor, but I doubt this is possible. Is there a proper way to solve this problem in C#?
nulltoval.DefaultDictionarywould be quite impractical...newto hide method has obvious downsides)