具有默认值的.net字典

具有默认值的.net字典,.net,dictionary,.net,Dictionary,我想要一个字典,它将为字典中不存在的任何键返回指定值,类似于: var dict = new DictWithDefValues("not specified"); dict.Add("bob78", "Smart"); dict.Add("jane17", "Doe"); Assert.AreEqual(dict["xxx"], "not specified"); 扩展System.Collections.Generics.Dictionary并重写TryGetValue无效,因为TryGe

我想要一个字典,它将为字典中不存在的任何键返回指定值,类似于:

var dict = new DictWithDefValues("not specified");
dict.Add("bob78", "Smart");
dict.Add("jane17", "Doe");
Assert.AreEqual(dict["xxx"], "not specified");
扩展System.Collections.Generics.Dictionary并重写TryGetValue无效,因为TryGetValue不是虚拟的

从头开始(从IDictionary)重新实现字典太费劲了

扩展方法不允许我用默认值“初始化”字典。我希望字典的使用者认为键在那里,而不仅仅是do
dict.GetOrDefault(键,“未指定”)

从头开始(从IDictionary)重新实现字典太费劲了

这确实是最好的选择。只需将
字典
封装为类的成员,并将所有成员传递给字典的代码。在这种情况下,您只需要处理希望不同的属性和方法


我同意这是一项有点枯燥的工作——但可能不到5分钟的打字时间,因为每个方法都可以传递给内部字典的实现。

我认为Reed的观点是正确的,重新实现字典非常简单,如果这是您需要的,那就好了

但是,创建一个新类来替换它似乎还是有些过分

        dict.TryGetValue("xxx", out value);
        value = value ?? "not specified";


我在.NET中创建了一个DefaultableDictionary,它完全符合您的要求

博客帖子。

试试这个

public class DefaultDictionary<Tkey,Tvalue>
    where Tkey: IEquatable<Tkey>
{
    private readonly Func<Tvalue> _getDefault;
    private Dictionary<Tkey, Tvalue> _dict;

    public DefaultDictionary(Func<Tvalue> getDefault = null)
    {
        if (getDefault == null)
        {
            _getDefault = () => default(Tvalue);
        }
        else
        {
            _getDefault = getDefault;
        }
        _dict = new Dictionary<Tkey, Tvalue>();
    }

    public Tvalue this[Tkey key]
    {
        get
        {
            if (!_dict.ContainsKey(key))
            {
                _dict[key] = _getDefault();
            }
            return _dict[key];
        }

        set { _dict[key] = value; }
    }

    public bool ContainsKey(Tkey key)
    {
        return _dict.ContainsKey(key);
    }

    public override string ToString()
    {
        var sb = new StringBuilder();
        foreach (var kvp in _dict)
        {
            sb.AppendFormat("[{0}] : {1}", kvp.Key.ToString(), kvp.Value.ToString()).AppendLine();
        }

        return sb.ToString();
    }
}
公共类DefaultDictionary
其中Tkey:IEquatable
{
私有只读函数_getDefault;
私人词典;
公共默认字典(Func getDefault=null)
{
if(getDefault==null)
{
_getDefault=()=>default(Tvalue);
}
其他的
{
_getDefault=getDefault;
}
_dict=新字典();
}
公共Tvalue此[Tkey]
{
得到
{
如果(!_dict.ContainsKey(键))
{
_dict[key]=\u getDefault();
}
返回_dict[键];
}
设置{u dict[key]=value;}
}
公共bool ContainsKey(Tkey)
{
返回目录ContainsKey(键);
}
公共重写字符串ToString()
{
var sb=新的StringBuilder();
foreach(var kvp输入)
{
AppendFormat(“[{0}]:{1}”,kvp.Key.ToString(),kvp.Value.ToString()).AppendLine();
}
使某人返回字符串();
}
}

您可以根据需要轻松地向其他方法和属性添加包装器。

我注意到您的示例是字符串字典。在我自己的场景中,我也需要类似的行为


也许好的
StringDictionary
类可以满足您的需要。与
Dictionary
不同,它的get\u Item方法为Dictionary中不存在的键返回
null

这个扩展方法让我通过

    public static TValue GetValueOrDefault<TKey, TValue>(this Dictionary<TKey, TValue> source, TKey key, TValue defaultValue = default(TValue))
    {
        TValue found;
        if (source.TryGetValue(key, out found))
        {
            return found;
        }
        else
        {
            return defaultValue;
        }
    }

问题是,我很少有消费者使用传递给他们的词典。这些使用者不知道(而且一定不知道,否则您会违反SRP)缺少条目的默认值是什么。因此,不,这不仅仅是替换它,而是替换:
someotherservicesresponsibleforhandlingmissingkeys.GetValueFor(key)
,那么在同样的情况下,您肯定需要使用Reed的方法。我收集了大量不同的业务对象类型。我希望通过使用Func字典来充分利用策略模式,这些字典应该返回标准Func或特殊情况Func,以防业务对象类型需要它。开闭原理。你们最后在这里用了什么?因为我的字典不大,所以我只填写遗漏的条目。我不会依赖你们索引器getter中的异常。改用
if(x.ContainsKey(…)
。既然可以委托,为什么还要复制/粘贴?我想OP想要实现IDictionary的东西。另外,我认为
if(!\u dict.ContainsKey(key)){…}
可以通过
if(!dict.TryGetValue(key,out v)){…}
更有效地实现。我不确定在查找失败时自动向基础映射添加条目是否有意义。我检查了Scala的可变映射,它没有表现出这种行为。但我可以预见到这两种情况。也许它应该是一个构造函数设置。
    public static TValue GetValueOrDefault<TKey, TValue>(this Dictionary<TKey, TValue> source, TKey key, TValue defaultValue = default(TValue))
    {
        TValue found;
        if (source.TryGetValue(key, out found))
        {
            return found;
        }
        else
        {
            return defaultValue;
        }
    }
dict.GetValueOrDefault("foo", 0) // returns the key under "foo", or 0 if missing.