Можно ли программно проверить, есть ли в enum инициализатор?

Я хочу получить enum как int, но только если к нему применен инициализатор - так что я знаю, что значение было определено явно, а не просто значением по умолчанию. Это потому, что я использую перечисления для представления сопоставления с определенными int кодами. Есть ли способ сделать это с помощью перечислений, или мне придется использовать что-то еще, например, словарь?

Вот пример - у меня есть следующее отображение:

Яблоки = 1, бананы = 2, груши = 4, ананасы = 7

Я хочу убедиться, что если enum

public enum Fruit
{
Apples,
Bananas,
Pears,
Pineapples
}

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

ОБНОВИТЬ:

Я использую nullable перечисления, чтобы проверить, было ли установлено значение (или неизвестный элемент), но это не то, что я спрашиваю здесь. Я не думаю, что я делаю очень хорошую работу, объясняя это, поэтому я попробую еще раз.

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

ДРУГОЕ ОБНОВЛЕНИЕ:

Я получил этот термин "инициализированный" из документации Microsoft, и я думаю, что он вызывает путаницу. Я имел в виду перечисление, в котором явно определены значения базовых целых. То есть,

public enum MyEnum
{
One = 1,
Two = 2,
Three = 3
}

в отличие от того, кто этого не делает. То есть,

public enum MyEnum
{
One,
Two,
Three
}

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

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

3 ответа

Решение

На уровне IL перечисление - это просто целое число (если оно не упаковано); Вы не можете сказать неявное 0 от явного 0, Nullable<SomeType> (ака SomeType?) может быть осуществимой идеей, хотя. Кроме этого: вам придется придумать какое-то локальное определение того, что это ноль против значения по умолчанию.

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

Fruit myFruit = (Fruit)12345;    // Some random integer

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

Fruit myFruit = (Fruit)12345;
int myFruitInt = (int)myFruit;

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

Fruit myFruit;
bool isDefined;

myFruit = Fruit.Bananas;
isDefined = Enum.IsDefined(typeof(Fruit), myFruit); // true, Bananas

myFruit = (Fruit)1;
isDefined = Enum.IsDefined(typeof(Fruit), myFruit); // true, Bananas

myFruit = Fruit.Bananas | Fruit.Pineapples;
isDefined = Enum.IsDefined(typeof(Fruit), myFruit); // false

myFruit = (Fruit)12345;
isDefined = Enum.IsDefined(typeof(Fruit), myFruit); // false

Конечно, вы можете поставить любой Type в методе, а не только typeof(Fruit),


Вы говорите об инициализированных перечислениях. Там нет такой вещи. Перечисление может иметь любое целочисленное значение. Значение по умолчанию для типов значений (включая перечисления) равно 0. Но вполне возможно (и даже рекомендуется), что существует константа перечисления со значением 0 (обычно с именем None, Unknown или же Default). Итак, семантически точно то же самое:

private Fruit myFruit;

private Fruit myFruit = (Fruit)0;

private Fruit myFruit = Fruit.Unknown;

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


Видимо документация MSDN по enum состояния:

По умолчанию первый перечислитель имеет значение 0, а значение каждого последующего перечислителя увеличивается на 1. Например, в следующем перечислении Sat равен 0, Sun равен 1, Mon равен 2 и т. Д.

enum Days {Sat, Sun, Mon, Tue, Wed, Thu, Fri};

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

enum Days {Sat=1, Sun, Mon, Tue, Wed, Thu, Fri};

В этом перечислении последовательность элементов принудительно начинается с 1 вместо 0. Однако рекомендуется включать константу со значением 0.

Я не уверен, что документация вызывает эти инициализаторы, так как ничего не инициализировано. Это просто синтаксис, чтобы сделать вашу жизнь проще. Вы также могли бы указать эквивалент:

enum Days {Sat=1, Sun=2, Mon=3, Tue=4, Wed=5, Thu=6, Fri=7};

Возможно, они имеют в виду, что 1 это начальное значение, с которого компилятор начнет отсчет, чтобы присвоить постоянное целочисленное значение константам перечисления, которые следуют за ним. Например:

enum Days {Sat, Sun=2, Mon, Tue=10, Wed, Thu, Fri=11};

Эквивалентно:

enum Days {Sat=0, Sun=2, Mon=3, Tue=10, Wed=11, Thu=12, Fri=11};

Опять же, ничего не инициализировано.

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

Лучшее решение - добавить запись enum, которая будет соответствовать значению 0. Например

public enum Fruit
{
    Unknown = 0,
    Apples,
    Bananas,
    Pears,
    Pineapples
}

Fruit someFruit;
if (someFruit == Fruit.Unknown)
    Console.WriteLine("fruit is not initialized");
else
    Console.WriteLine("fruit is initialized");

Другой способ приблизиться к этому - заключить значение в Nullable. Таким образом, вы позволите переменной быть установленной в null,

public enum Fruit
{
    Apples,
    Bananas,
    Pears,
    Pineapples
}

Fruit? someFruit;
if (!someFruit.HasValue)
    Console.WriteLine("fruit is not initialized");
else
    Console.WriteLine("fruit is initialized");
Другие вопросы по тегам