【问题标题】:.net dictionary with default value具有默认值的 .net 字典
【发布时间】:2011-05-04 01:13:07
【问题描述】:

我想要一个字典,它可以为不在字典中的任何键返回指定值,例如:

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)太费力了。

扩展方法不会让我用默认值“初始化”字典。我希望字典的消费者认为钥匙在那里,而不仅仅是dict.GetOrDefault(key, "not specified");

【问题讨论】:

  • 我也有同样的情况。我收集了大量的各种业务对象类型。我想通过具有应该返回标准 Func 或特殊情况 Func 的 Func 字典来极端使用策略模式,以防业务对象类型允许它。开闭原则。你最终在这里使用了什么?
  • 由于我的字典不大,所以我只填了缺失的条目。

标签: .net dictionary


【解决方案1】:

这个扩展方法让我通过;

    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.

【讨论】:

    【解决方案2】:

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

    也许旧的 StringDictionary 类会做你想做的事。与 Dictionary&lt;string,string&gt; 不同,它的 get_Item 方法为字典中不存在的键返回 null

    【讨论】:

      【解决方案3】:

      试试这个

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

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

      【讨论】:

      • 我认为 OP 想要实现 IDictionary 的东西。另外,我认为使用if (!dict.TryGetValue(key, out v)) { ... } 可以更有效地实现if (!_dict.ContainsKey(key)) { ... }。我不确定当查找失败时自动将条目添加到底层地图是否有意义。我检查了 Scala 的可变映射,它没有表现出这种行为。但我可以看到无论哪种方式。也许它应该是一个构造函数设置。
      【解决方案4】:

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

      http://github.com/jsonmez/Defaultable-Dictionary

      博文here

      【讨论】:

      • 我不会依赖你的 indexer-getter 中的异常。请改用if (x.ContainsKey(...))
      【解决方案5】:

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

      但是创建一个新类来替换似乎还是有点矫枉过正

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

            value  = dict.GetOrDefault(key, "not specified")
      

      【讨论】:

      • 好吧,问题是我很少有消费者使用传递给他们的字典。这些消费者不知道(并且一定不知道,否则您会违反 SRP)丢失条目的默认值是什么。所以不,它不只是替换它,而是替换:someOtherServiceResponsibleForHandlingMissingKeys.GetValueFor(key)
      • 那你肯定要走里德的方法
      【解决方案6】:

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

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

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

      【讨论】:

      • 既然可以委托,为什么还要复制/粘贴?
      猜你喜欢
      • 1970-01-01
      • 2016-06-25
      • 2016-01-28
      • 2018-05-27
      • 2011-06-29
      • 2021-02-10
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多