2008-11-06 3 views
88

Что представляет собой наиболее эффективный способ создания постоянной (никогда не меняется во время выполнения) картирование string s до int s?Создание константного словаря в C#

Я пробовал использовать const Dictionary, но это не сработало.

Я мог бы реализовать immutable wrapper с соответствующей семантикой, но это все еще кажется не совсем правильным.


Для тех, кто просил, я реализации IDataErrorInfo в созданном классе, и я искал способ, чтобы сделать поиск ColumnName в мой массив дескрипторов.

Я не знал (опечатка при тестировании! D'oh!), Что переключатель принимает строки, так вот что я буду использовать. Благодаря!

+0

есть решение здесь: http://stackoverflow.com/questions/10066708/readonly-keyword-does-not -make-a-list-readonly – 2013-08-16 14:48:59

ответ

132

Создание действительно время компиляции генерируется постоянный словарь в C# на самом деле не простая задача. На самом деле, ни один из ответов здесь действительно не достигает этого.

Существует одно решение, которое отвечает вашим требованиям, хотя и не обязательно приятным; помните, что в соответствии со спецификацией C# таблицы switch-case скомпилированы в постоянные таблицы перехода хэша. То есть, они являются постоянными словарями, а не серией операторов if-else. Поэтому рассмотрим дело с коммутационным случаем следующим образом:

switch (myString) 
{ 
    case "cat": return 0; 
    case "dog": return 1; 
    case "elephant": return 3; 
} 

Это именно то, что вы хотите. И да, я знаю, это уродливо.

+17

Эй, я что-то узнал. – mackenir 2008-11-06 10:36:37

+7

Это сгенерированный код в любом случае, обладает хорошими характеристиками производительности, может быть рассчитан на компиляцию и имеет другие приятные свойства для моего прецедента. Я буду делать это так! – 2008-11-06 13:21:53

1

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

Edit: Марк Gravell нашел ILookup, что я пропустил - что позволит, по крайней мере, избежать создания новой оболочки, хотя вам все еще нужно преобразовать словарь с .ToLookup().

Если это необходимо ограничены в конкретном случае, вы могли бы быть лучше с более бизнес-логика-ориентированного интерфейса:

interface IActiveUserCountProvider 
{ 
    int GetMaxForServer(string serverName); 
} 
31

Есть несколько драгоценных неизменные коллекции в рамках нынешней системы. Я могу думать об одном относительно безболезненном варианте в .NET 3.5:

Использование Enumerable.ToLookup() - класс Lookup<,> является неизменным (но многозначным на rhs); Вы можете сделать это с Dictionary<,> довольно легко:

Dictionary<string, int> ids = new Dictionary<string, int> { 
     {"abc",1}, {"def",2}, {"ghi",3} 
    }; 
    ILookup<string, int> lookup = ids.ToLookup(x => x.Key, x => x.Value); 
    int i = lookup["def"].Single(); 
12
enum Constants 
{ 
    Abc = 1, 
    Def = 2, 
    Ghi = 3 
} 

... 

int i = (int)Enum.Parse(typeof(Constants), "Def"); 
+1

Интересная идея! Мне интересно, насколько хорош вызов Parse(). Я боюсь, что только профилировщик может ответить на этот вопрос. – 2008-12-16 10:02:33

9

Это самая близкая вещь вы можете добраться до «ФИКС словаря»:

public static int GetValueByName(string name) 
{ 
    switch (name) 
    { 
     case "bob": return 1; 
     case "billy": return 2; 
     default: return -1; 
    } 
} 

Компилятор будет достаточно умен, чтобы построить код как можно более чистым.

0

Почему нет:

public class MyClass 
{ 
    private Dictionary<string, int> _myCollection = new Dictionary<string, int>() { { "A", 1 }, { "B", 2 }, { "C", 3 } }; 

    public IEnumerable<KeyValuePair<string,int>> MyCollection 
    { 
     get { return _myCollection.AsEnumerable<KeyValuePair<string, int>>(); } 
    } 
}