Проблема с перечислением в качестве ключа в коллекции словаря - PullRequest
5 голосов
/ 05 марта 2010

У меня есть сценарий, в котором я использую Словарь для хранения списка типов транзакций, которые принимает определенная система. Ключ в словаре - это поле enum, значение - int.

В какой-то момент в системе мы захотим сделать что-то вроде этого:

sqlCommand.Parameters.AddWithValue("@param", LookupDictionary[argument.enumField]);

Когда мы ищем поле в словаре, мы собираемся получить правильное целочисленное значение для подачи в базу данных. Я думал о том, чтобы фактически использовать для этого значение enum int, но это не совсем верно. Мы взаимодействуем с системой, в которой нам нужно ввести магическое число, чтобы представить тип обновления, которое мы делаем.

Код выше работает просто отлично. У меня есть метод инициализатора, который добавляет известные типы:

LookupDictionary = new Dictionary<mynamespace.myproject.myclass.enumType, int>();
LookupDictionary.Add(enumType.entry1, 4);
LookupDictionary.Add(enumType.entry2, 5);
LookupDictionary.Add(enumType.entry3, 6);

Этот код также отлично работает.

Но выше, прежде чем я на самом деле использую LookupDictionary, я проверяю, что выполняемый запрос на самом деле установлен в значение enum, которое мы поддерживаем. Это главная причина LookupDictionary, он содержит действительные (есть допустимые записи enum, с которыми этот метод не работает).

Это код, который не работает: система не может распознать, что перечисления совпадают. В отладчике я вижу, что список записей в LookupDictionary действительно показывает, что он имеет значение для entry2 - он просто вызывает его вот так, entry2. Входящий enumField, с другой стороны, имеет полное пространство имен; mynamespace.myproject.myclass.enumType.entry2 - я думаю, именно поэтому он не видит их как одинаковые.

if (!LookupDictionary.ContainsKey(argument.enumField))
{
    throw new InvalidOperationException("argument.enumField not valid in blahMethod.");
}

Я упоминал, что это передается через службу WCF? Но я не использую автоматически сгенерированный прокси ... оба проекта на обеих сторонах провода делят типы в качестве ссылки на проект, и я строю свой клиент канала в коде.

Есть идеи? Я делаю это неправильно? Словари с Enums в качестве ключей не работают? Это вещь WCF?

Примечание: спасибо за предложения относительно установки перечислений для содержания magic int. Однако я хотел установить их в конфигурации, так как возможно, что «магические числа» 4 5 и 6 могут измениться в будущем. Поэтому, если я закодирую их в перечислении, как предложено:

public enum MyEnum
{
    MyValue1 = 4,
    MyValue2 = 5,
    MyValue3 = 6
}

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

Ответы [ 4 ]

3 голосов
/ 05 марта 2010

Вместо использования перечисления в качестве ключа используйте целочисленное представление перечисления.

Например:

LookupDictionary = new Dictionary<int, int>();
LookupDictionary.Add((int)enumType.entry1, 4);
LookupDictionary.Add((int)enumType.entry2, 5);
LookupDictionary.Add((int)enumType.entry3, 6);

Таким образом, вы можете использовать тот же метод словаря ContainsKey. Я не уверен, что это намного лучшая производительность, чем List<int>

1 голос
/ 05 марта 2010

Вам вообще не нужна таблица соответствия:

public enum MyEnum
{
    MyValue1 = 4,
    MyValue2 = 5,
    MyValue3 = 6
}

// Sample usage
MyEnum firstEnum = MyEnum.MyValue1;
int intVal = (int)firstEnum;    // results in 4

// Enum Validation
bool valid = Enum.IsDefined(typeof(MyEnum), intVal);   // results in true
0 голосов
/ 05 марта 2010

Вы можете явно установить значения перечисления, используя синтаксис

enum ArgumentTypes {
    Arg1 = 1;
    Arg2 = 3;
    Arg3 = 5;
}

Вам не нужно хранить каждое значение последовательно в перечислении, чтобы этот синтаксис работал.

Чтобы проверить, что когда-либо используются только параметры, допустимые для метода, попробуйте этот пример кода. Примечание. В этом контексте я предлагаю использовать ArgumentException вместо InvalidOperationException.

public void DoDbWork(ArgumentTypes argType, object otherParameter)
{
    if (argType == ArgumentTypes.Arg3) {
        throw new ArgumentException("Argument of value " + argType + " is not valid in this context", "argType");
    }

    // Handle db transaction here
}

Чтобы добавить значение int в качестве параметра:

cmd.Parameters.AddWithValue("@paramName", (int)argType);
0 голосов
/ 05 марта 2010

Можете ли вы подумать о том, чтобы вводить свое перечисление в явном виде как int (или каков бы ни был базовый тип), а затем устанавливать значение каждого из ваших перечислений в значение базы данных? Вы уже тесно связали перечисление с базой данных, поэтому либо связь будет определяться в C # (текущее жесткое кодирование) или SQL (возможно, proc, который возвращает идентификатор, а также строку, которую можно проанализировать в перечислении .)

Используя предположение, что ваше перечисление является целым ...

enum enumType {
    entry1 = 4,
    entry2 = 5,
    entry3 = 6
}

При добавлении вашего параметра вы просто будете использовать базовый тип перечисления.

sqlCommand.Parameters.AddWithValue("@param", (int)argument.enumField);
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...