2013-04-02 2 views
0

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

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

яблоки = 1, Бананы = 2, Груши = 4, ананасы = 7

Я хочу, чтобы убедиться, что если перечисление является

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

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

UPDATE:

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

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

ДРУГОЙ UPDATE:

Я получил этот термин «инициализирован» от Microsoft documentation, и я думаю, что это вызывает путаницу. То, что я имел в виду, - это перечисление, в котором явно указано значение базовых ints. I.e.,

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

в отличие от того, который этого не делает. Т.е.,

public enum MyEnum 
{ 
One, 
Two, 
Three 
} 

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

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

+3

Я всегда устанавливаю значение 'Unknown = 0' в моем Enum будет сериализован, поэтому я всегда могу знать, что 0 = undefined. – asawyer

+0

@asawyer хорошая идея, я всегда начинаю первое значение в 1. – usr

+0

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

ответ

1

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

+0

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

+0

@ dustmouse * how * они могли бы поддержать это, на ваш взгляд? Перечислением может быть любое целочисленное значение (поэтому остаточных значений не осталось). Для этого реализация перечислений должна быть очень различной. –

+0

Да, базовая реализация будет отличаться. Для отслеживания того, была ли инициализирована int или по умолчанию, потребуется немного больше памяти. Почему они не могут это сделать? (Я не говорю, что они должны или что я действительно этого хочу.) – lintmouse

0

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

Лучшим решением является добавление записи перечисления, которая соответствует значению 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"); 
+0

Это не решение этого вопроса. Обновление более понятно. – Virtlink

0

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

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

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

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

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

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. Например, в следующем перечисление, Сб = 0, Солнце 1, Пн - 2 и т. д.

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

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

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

В этом перечислении, последовательность элементов вынужден начать с 1 вместо 0. Тем не менее, в том числе константой, имеющей значение 0 рекомендуется.

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

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

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

+0

В моем случае я не буду пытаться получить элемент по его int. Я получаю int для элемента. Я просто хочу знать, можно ли определить, инициализируется ли int или по умолчанию. – lintmouse

+0

@dustmouse Вы говорите о _initialized_, но такой вещи нет. См. Мое обновление. – Virtlink

+0

Проверьте эту ссылку. Он говорит об инициализированных перечислениях в начале: http://msdn.microsoft.com/en-us/library/sbbt4032(v=vs.71).aspx – lintmouse