C# 泛型类型约束取决于使用的构造函数

时间:2021-03-23 13:26:06

标签: c# generics type-constraints

我想在 C# 中模仿 Python collections.defaultdict。只要值类型具有无参数构造函数,以下就可以正常工作:

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; }
    }
}

但是如果我想使用一个以键为参数的构造函数呢?或者一般来说,一个工厂函数,给定键,返回值类型的实例?

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; }
    }
}

现在的问题是 TValue 仍然需要有一个无参数的构造函数,即使使用了工厂函数。如果 Thingy 没有无参数构造函数,以下将不会编译:

new DefaultDictionary<int, Thingy>(key => new Thingy(key, otherStuff, moreStuff));

但是,删除约束会导致 new TValue() 语句中出现 CS0304 错误。

直觉上我想将类型约束放在 DefaultDictionary() 构造函数上,但我怀疑这是可能的。 C#有没有合适的方法可以解决这个问题?

1 个答案:

答案 0 :(得分:1)

一种方法是仅保留采用 DefaultDictionary 中的值工厂的构造函数,并创建一个具有 : new() 约束的子类,并将无参数构造函数移到那里:

public class DefaultDictionaryParameterless<TKey, TValue> :
    DefaultDictionary<TKey, TValue> where TValue : new()
{
    public DefaultDictionaryParameterless()
        : base(x => new TValue())
    {
        
    }
}

public class DefaultDictionary<TKey, TValue> : Dictionary<TKey, TValue>
{
    private readonly Func<TKey, TValue> factory;

    public DefaultDictionary(Func<TKey, TValue> factory)
    {
        this.factory = factory;
    }
    ...
}