代码之家  ›  专栏  ›  技术社区  ›  chilltemp

在字典和集合上自动添加索引器是一个好的设计决策吗?

  •  8
  • chilltemp  · 技术社区  · 16 年前

    public class I { /* snip */  }
    public class D : Dictionary<string, I>
    {
        public I this[string name]
        {
            get
            {
                I item;
                if (!this.TryGetValue(name, out item))
                {
                    item = new I();
                    this.Add(name, item);
                }
                return item;
            }
        }
    }
    

    如何在集合中使用的示例:

    public class I
    {
        public I(string name) {/* snip */}
        public string Name { get; private set; }
        /* snip */
    }
    public class C : Collection<I>
    {
        private Dictionary<string, I> nameIndex = new Dictionary<string, I>();
    
        public I this[string name]
        {
            get
            {
                I item;
                if (!nameIndex.TryGetValue(name, out item))
                {
                    item = new I(name);
                    this.Add(item); // Will also add the item to nameIndex
                }
                return item;
            }
        }
    
        //// Snip: code that manages nameIndex 
        // protected override void ClearItems()
        // protected override void InsertItem(int index, I item)
        // protected override void RemoveItem(int index)
        // protected override void SetItem(int index, I item)
    }
    
    6 回复  |  直到 16 年前
        1
  •  12
  •   LBushkin    16 年前

    有两个问题,你应该考虑-这两个都表明这是一个坏主意。

    首先,从.NETBCL集合类型继承通常不是一个好主意。主要原因是这些类型上的大多数方法(如 Add Remove Dictionary<TK,TV> 如果是indexer属性,则您正在创建一种情况,其中使用基类引用的调用将执行与使用派生类引用的调用不同的操作。。。违反法律 Liskov Substitution Principle :

    var derived = new D();
    var firstItem = derived["puppy"]; // adds the puppy entry
    
    var base = (Dictionary<string,I>)derived;
    var secondItem = base["kitten"]; // kitten WAS NOT added .. BAD!
    

    ,创建一个索引器,在尝试查找项目时插入项目 . 索引器已明确定义 get set 操作-实施 得到

    对于您描述的情况,最好创建一个可以对任何字典进行操作的扩展方法。这样的操作既不那么令人惊讶,也不需要创建派生集合类型:

    public static class DictionaryExtensions
    { 
        public static TValue FindOrAdd<TKey,TValue>( 
                 this IDictionary<TKey,TValue> dictionary, TKey key, TValue value )
            where TValue : new()
        { 
            TValue value; 
            if (!this.TryGetValue(key, out value)) 
            { 
                value = new TValue(); 
                this.Add(key, value); 
            } 
            return value; 
        } 
    }
    
        2
  •  3
  •   mqp    16 年前

    AutoInitializingDictionary 或者什么)什么是预期的。

    我个人更倾向于将此作为一种方法而不是索引器;类似于 D.FindOrCreate . (我感觉有一个惯用的名字来代表一个我暂时忘记的方法。)

        3
  •  3
  •   Conrad Frix    16 年前

    我想说这违反了两个原则。1) 最小意外原则。2)getter不应该改变任何事情。

    如果集合中不存在foo,我就不希望在对{“foo”,null}中添加一个。

    x = collection["Foo"]
    
        4
  •  2
  •   Ani    16 年前

    public class DefaultValueDictionary<K, V> : IDictionary<K, V>
    {
      public DefaultValueDictionary(IDictionary<K, V> baseDictionary, Func<K, V> defaultValueFunc)
      {
        ...
      }
    }
    

    public class ParameterlessCtorDefaultValueDictionary<K, V> 
                : DefaultValueDictionary<K, V> where V : new()
    {
      public ParameterlessCtorDefaultValueDictionary(IDictionary<K, V> baseDictionary)
         : base(baseDictionary, k => new V())
      {
        ...
      }
    }
    

    IDictionary<K,List<V>> ; 我能做到

    var dict = new ParameterlessCtorDefaultValueDictionary<string, int>();
    ...
    dict[key]++;
    

    而不是辛苦的工作:

    int count;
    if(!dict.TryGetValue(key, out count))
      dict[count] = 1;
    else dict[count] = count + 1;
    
        5
  •  2
  •   Gabe Timothy Khouri    15 年前

        6
  •  0
  •   TheSoftwareJedi jac    15 年前

    索引器什么时候可以接受 收藏/词典?

    从未

    最佳实践?

    也就是说,如果类的名称恰当,它是可以接受的。我个人会用 GetOrAdd 相反。