.NET: переключение против словаря для строковых ключей - PullRequest
11 голосов
/ 26 августа 2009

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

object GetFieldValue(string FieldName);

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

Используйте оператор 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 быть быстрее и проще в обслуживании ...

Ответы [ 4 ]

21 голосов
/ 26 августа 2009
switch:      good efficiency, least maintainable
dictionary:  good efficiency, better maintainability
reflection:  least efficient, best maintainability

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

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

7 голосов
/ 26 августа 2009

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

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

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

0 голосов
/ 17 февраля 2017

Switch фактически имеет 2 преимущества по сравнению со словарем:

  1. Вы можете создать настроенное сообщение об исключении в разделе по умолчанию, которое может содержать недопустимое значение. В случае словаря вы получаете только исключение KeyNotFoundException, которое не содержит имени ключа.
  2. Вы можете обрабатывать нулевые значения. Словарь не может хранить ноль в качестве ключа.
0 голосов
/ 26 августа 2009

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

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

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

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

Я хочу сказать, прежде чем вы начнете оптимизировать, используйте профилировщик. (Конечно, если вы не можете изменить сетку, вы не сможете ее оптимизировать)

...