Являются ли автоматическое добавление индексаторов в словари и коллекции хорошим решением для разработки

Когда для индексатора допустимо автоматическое добавление элементов в коллекцию / словарь? Разумно ли это или противоречит передовому опыту?

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)
}
8
задан chilltemp 27 August 2010 в 21:26
поделиться

4 ответа

Я бы сказал, что это нарушает два принципа. 1) принцип наименьшего удивления. И 2) что геттеры не должны ничего менять.

Я бы не стал добавлять пару {"foo", null}, если foo не существует в коллекции.

x = collection["Foo"]
3
ответ дан 5 December 2019 в 07:33
поделиться

Без какой-либо другой информации о том, что вы делаете, такое поведение кажется мне удивительным. Я надеюсь, что вы ясно из контекста (например, назовите его AutoInitializingDictionary или что-то в этом роде), чего следует ожидать.

Лично я предпочел бы сделать это методом, а не индексатором; что-то вроде D.FindOrCreate. (У меня такое чувство, что есть идиоматическое название для метода, который делает это, но я временно забыл.)

3
ответ дан 5 December 2019 в 07:33
поделиться

Я думаю, что это совершенно нормально, пока такое поведение совершенно ясно. У меня есть 2 класса декораторов:

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>; Я могу сделать

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

вместо утомительного:

int count;
if(!dict.TryGetValue(key, out count))
  dict[count] = 1;
else dict[count] = count + 1;
2
ответ дан 5 December 2019 в 07:33
поделиться

Основная причина, по которой я был бы обеспокоен, заключается в том, что это не будет потокобезопасным. Несколько читателей, пытающихся одновременно писать в Словарь, потребуют тщательного управления блокировками, о котором вы, вероятно, не подумали бы (или не поняли бы правильно) поначалу.

2
ответ дан 5 December 2019 в 07:33
поделиться
Другие вопросы по тегам:

Похожие вопросы: