.NET: switch vs dictionary для строковых ключей

У меня есть ситуация, когда у меня есть бизнес-объект с 15 свойствами разных типов. Бизнес-объект также должен реализовать интерфейс, который имеет следующий метод:

object GetFieldValue(string FieldName);

Я вижу два способа реализации этого метода:

Используйте оператор switch:

switch ( FieldName )
{
    case "Field1": return this.Field1;
    case "Field2": return this.Field2;
    // etc.
}

Используйте словарь (SortedDictionary или HashTable?):

return this.AllFields[FieldName];

Что было бы более эффективным?

Добавлено: Забыл сказать. Этот метод предназначен для отображения элемента в сетке. У сетки будет столбец для каждого из этих свойств. Обычно в них будут решетки с чуть более 1000 предметов. Вот почему меня беспокоит производительность.

Добавлен 2:

Вот идея: гибридный подход. Сделайте статический словарь с ключами, являющимися именами свойств, и значениями являются индексы в массиве. Словарь заполняется только один раз, при запуске приложения. Каждый экземпляр объекта имеет массив. Таким образом, поиск будет выглядеть следующим образом:

return this.ValueArray[StaticDictionary[FieldName]];

Алгоритм заполнения словаря может использовать отражение. Затем сами свойства будут реализованы:

public bool Field1
{
    get
    {
        object o = this.ValueArray[StaticDictionary["Field1"]]; 
        return o == null ? false : (bool)o;
    }
    set
    {
        this.ValueArray[StaticDictionary["Field1"]] = value;
    }
}

Может ли кто-нибудь увидеть какие-либо проблемы с этим?

Также можно сделать еще один шаг, а ValueArray/StaticDictionary можно поместить в отдельный общий тип ValueCollection<T>, где T будет указывать тип для отражения. ValueCollection также будет обрабатывать случай, когда значение еще не установлено. Затем свойства можно было бы написать просто так:

public bool Field1
{
    get
    {
        return (bool)this.Values["Field1"];
    }
    set
    {
        this.Values["Field1"] = value;
    }
}

И в конце я снова начинаю удивляться, если простой оператор switch может быть не быстрее и проще поддерживать....

Ответ 1

switch:      good efficiency, least maintainable
dictionary:  good efficiency, better maintainability
reflection:  least efficient, best maintainability

Подсказка: игнорировать эффективность и беспокоиться только об обслуживании, если только вы не протестировали производительность и не обнаружили проблемы.

Я не говорю, что размышление - это ваш единственный выбор, просто чтобы он мог добавлять/удалять и переименовывать свойства по мере необходимости, и не нужно синхронизировать оператор switch или словарь.

Ответ 2

Потому что вы используете строки Словарь, вероятно, будет быстрее. Переключатель по существу будет переведен на хеш-таблицу при использовании строк. Но если вы используете ints или подобное, он переводится в таблицу переходов и будет быстрее.

см. этот ответ и вопрос для более подробной информации

Лучше всего профилировать его и найти наверняка

Ответ 3

Как вы получите значение каждого свойства, вероятно, окажет меньшее влияние на общую производительность, чем на то, как вы рендерите свою сетку.

Позвольте мне привести пример: скажем, у вас есть следующая реализация:

private string _latestFieldName = string.Empty;
private PropertyInfo _propertyInfo;

object GetFieldValue(string FieldName)
{
  if(FieldName != _latestFieldName)
  {
    _propertyInfo = typeof(yourTypeName).GetProperty(FieldName);
  }
  return _propertyInfo.GetValue(this,null);
}

Если ваш рендеринг сетки отображает строку за раз, используя отражение, ей нужно будет получить свойствоinfo каждый раз. Если вы создадите столбец по столбцу, вам нужно будет получить значение propertyInfo один раз для каждого свойства, и поскольку предсказание ветки будет правильным почти каждый раз, когда вы будете пропускать очень мало тактовых циклов на if. Когда у вас уже есть PropertyInfo, и вам не нужно передавать результат вызова GetValue. используя отражение, ОЧЕНЬ близко к использованию получателя свойства, когда дело доходит до скорости.

Моя задача - до того, как вы начнете оптимизировать использование профилировщика. (Конечно, если вы не можете правильно изменить сетку, вы тоже не можете ее оптимизировать)

Ответ 4

У коммутатора действительно есть 2 преимущества по сравнению со словарем:

  • Вы можете создать настраиваемое сообщение об исключении в разделе по умолчанию, которое может включать недопустимое значение. В случае словаря вы получаете только KeyNotFoundException, который не содержит имени ключа.
  • Вы можете обрабатывать нулевые значения. Словарь не может хранить нуль в качестве ключа.