Использование hashcode для генерации значения для перечисления

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

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

Итак, я задавался вопросом об использовании хэш-кода имени значения Enum в качестве строки, что довольно легко создать script для.

Это хорошая идея? У меня будут проблемы с отрицательными значениями, которые может вернуть hashcode?

ИЗМЕНИТЬ Для тех, кто спрашивает, почему, я цитирую связанный "угловой случай":

Для сборки с помощью:

enum MyEnum
{
    Red,
    Blue,
}

если вы используете MyEnum.Red.ToString() в другой сборке, и между ними кто-то перекомпилировал ваше перечисление:

enum MyEnum
{
    Black,
    Red,
    Blue,
}

во время выполнения вы получите "Черный".

(NB, меня здесь не особенно интересует ToString, проблема в том, что если вызывающий код запрашивает MyEnum.Red, он действительно ссылается на MyEnum.Black)

Еще один пример, иллюстрирующий проблему с явной последовательной нумерацией:

enum ECountry
{
    Afghanistan = 1,
    Barbados = 2,
    Chile = 3,
    ...
    Zambia = 243, 
}

Если Giggleswick вдруг объявляет себя республикой, что вы делаете?

Ответы

Ответ 1

Нет, это не очень хорошая идея.

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

Просто используйте имя значения перечисления, если вам нужно конвертировать из одной версии перечисления в другую. Метод ToString дает вам имя, и вы можете использовать метод Enum.Parse для получения значения перечисления из строки.

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

Ответ 2

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

Хотя, я бы скорее просто установил значения явно 1, 2, 3 и так далее.

Ответ 3

Хэш-код двух разных строковых значений не гарантированно является уникальным, поэтому это выглядит как опасный вариант. В чем проблема с установкой значений явно? Если числа не имеют смысла в вашей объектной модели, то, похоже, нет причин оставлять место для новых значений - просто добавьте новые параметры в конец перечисления.

Ответ 4

Я не уверен, что я неправильно интерпретирую вещи или нет, но...

MyEnum.Red.ToString() должен давать "красный", а не 0. Как таковой Enum.Parse должно быть хорошо с правильной оценкой строки. Проблема, которую вы описываете, будет int Foo = (int) MyEnum.Red; Который будет 0; Это может привести к непоследовательным результатам, описанным после перекомпиляции с новыми элементами.

Основываясь на моем понимании требований, enum.ToString сохраняется, проблем не должно быть. Проблема заключается в сохранении значения или перечисления, а не строкового представления. Поэтому не требуется никакого хеширования.

Вот пример (притвориться, что мы добавили черный)...

 class Program
 {
  static void Main(string[] args)
  {
   // this is the approach described
   string RedToString = MyEnum.Red.ToString();

   // We're pretending that red was the zeroth element when we did (int)MyEnum.Red;
   int RedToInt = 0;

   MyEnum RedFromString = (MyEnum)Enum.Parse(typeof(MyEnum), RedToString);
   MyEnum RedFromInt = (MyEnum)RedToInt;

   // this is in theory how RedToInt was persisted
   int BlackFromInt = (int)MyEnum.Black;

   Console.WriteLine("RedToString: " + RedToString); // Red
   Console.WriteLine("RedToInt: " + RedToInt); // 0
   Console.WriteLine("RedFromString: " + RedFromString); // Red
   Console.WriteLine("RedFromInt: " + RedFromInt); // Black
   Console.WriteLine("BlackFromInt: " + BlackFromInt); // 0
   Console.Read();
  }

  enum MyEnum
  {
   Black,
   Red,
   Blue,
  }
 }

НТН, Бен