Pergunta

I want to get an enum as an int, but only if it has an initializer applied to it - so that I know that the value was explicitly defined and isn't just the default value. This is because I am using enums to represent a mapping with defined int codes. Is there a way to do this with enums, or am I going to have to use something else like a dictionary?

Here is an example - I have the following mapping:

Apples = 1, Bananas = 2, Pears = 4, Pineapples = 7

I want to make sure that if the enum is

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

that it won't try to get the int value, because a value of 1 in the enum corresponds to Bananas, not Apples, like it should. Let me know if I need to be more clear.

UPDATE:

I use nullable enums to check if the value was set (or an Unknown element), but that's not what I'm asking here. I don't think I'm doing a very good job explaining it so I'll try again.

I want to be able to get an enum that I know nothing about, take the underlying int and then do something with it. The only thing I care about is that the enum was initialized because it tells me that it has actual codes defined on it. I don't mind if it's null. That is one of the things I check for. But if it isn't null, I want to make sure that the int code is explicitly defined. A code of 0 is totally acceptable - even if it means that it is undefined - as long as that is what the original mapping specifies.

ANOTHER UPDATE:

I got this term 'initialized' from the Microsoft documentation and I think it is causing confusion. What I meant was an enum that has the value of the underlying ints explicitly defined on it. I.e.,

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

as opposed to one that doesn't. I.e.,

public enum MyEnum
{
One,
Two,
Three
}

I think it was also causing confusion that I was referring to these as having the default value set, which is easy to confuse with non-nullable enums that have the first element set by default.

The way that I'm using this is that I have a method that uses reflection to get the value of properties that have certain custom attributes on them. For my purposes, I only want to get the value from enums that have codes explicitly defined on them. Otherwise I can't assume that the int value has any business meaning.

Foi útil?

Solução

At the IL level, an enum is just an integer (unless it is boxed); you cannot tell an implicit 0 from an explicit 0. A Nullable<SomeType> (aka SomeType?) might be a workable idea though. Other than that: you'll have to come up with some local definition of what a zero vs default it.

Outras dicas

Enums are actually ordinal value types underneath, so they cannot be null, and similar solution cannot be applied.

Best solution is to add enum entry which would correspond to value 0. E.g.

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");

Another way to approach it would be to wrap a value into a Nullable. This way you would allow a variable to be set to 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");

A (non-nullable) enum value is always a valid integer. Therefore it is possible to get values that are not used by any of the constants in the enum:

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

And the other way around: you can always get the integer value of any enum, regardless of whether its value is defined as a constant or not.

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

Therefore, if you want to be sure the value of the enum is one of the values defined in the enum's definition, you can use the Enum.IsDefined method, like this:

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

Of course, you can put any Type in the method, not just typeof(Fruit).


You talk about initialized enums. There is no such thing. An enum can have any integer value. The default value for value types (including enums) is 0. But it is entirely possible (and even recommended) that there is a enum constant with a value of 0 (usually named None, Unknown or Default). So, the following are semantically exactly the same:

private Fruit myFruit;

private Fruit myFruit = (Fruit)0;

private Fruit myFruit = Fruit.Unknown;

You cannot tell the difference at run-time, because there is no difference.


Apparently the MSDN documentation on enum states:

By default, the first enumerator has the value 0, and the value of each successive enumerator is increased by 1. For example, in the following enumeration, Sat is 0, Sun is 1, Mon is 2, and so forth.

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

Enumerators can use initializers to override the default values, as shown in the following example.

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

In this enumeration, the sequence of elements is forced to start from 1 instead of 0. However, including a constant that has the value of 0 is recommended.

I'm not sure wht the documentation calls these initializers, since there is nothing initialized. It is just syntax to make your life easier. You could just as well have specified the equivalent:

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

Perhaps they mean that 1 is the initial value from which the compiler will start counting to assign a constant integer value to the enum constants that follow it. For example:

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

Is equivalent to:

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

Again, nothing is initialized.

Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top