How can I cast int to enum?

1,764,165

Solution 1

From an int:

YourEnum foo = (YourEnum)yourInt;

From a string:

YourEnum foo = (YourEnum) Enum.Parse(typeof(YourEnum), yourString);

// The foo.ToString().Contains(",") check is necessary for enumerations marked with an [Flags] attribute
if (!Enum.IsDefined(typeof(YourEnum), foo) && !foo.ToString().Contains(","))
{
    throw new InvalidOperationException($"{yourString} is not an underlying value of the YourEnum enumeration.")
}

Update:

From number you can also

YourEnum foo = (YourEnum)Enum.ToObject(typeof(YourEnum) , yourInt);

Solution 2

Just cast it:

MyEnum e = (MyEnum)3;

You can check if it's in range using Enum.IsDefined:

if (Enum.IsDefined(typeof(MyEnum), 3)) { ... }

Solution 3

Alternatively, use an extension method instead of a one-liner:

public static T ToEnum<T>(this string enumString)
{
    return (T) Enum.Parse(typeof (T), enumString);
}

Usage:

Color colorEnum = "Red".ToEnum<Color>();

OR

string color = "Red";
var colorEnum = color.ToEnum<Color>();

Solution 4

I think to get a complete answer, people have to know how enums work internally in .NET.

How stuff works

An enum in .NET is a structure that maps a set of values (fields) to a basic type (the default is int). However, you can actually choose the integral type that your enum maps to:

public enum Foo : short

In this case the enum is mapped to the short data type, which means it will be stored in memory as a short and will behave as a short when you cast and use it.

If you look at it from a IL point of view, a (normal, int) enum looks like this:

.class public auto ansi serializable sealed BarFlag extends System.Enum
{
    .custom instance void System.FlagsAttribute::.ctor()
    .custom instance void ComVisibleAttribute::.ctor(bool) = { bool(true) }

    .field public static literal valuetype BarFlag AllFlags = int32(0x3fff)
    .field public static literal valuetype BarFlag Foo1 = int32(1)
    .field public static literal valuetype BarFlag Foo2 = int32(0x2000)

    // and so on for all flags or enum values

    .field public specialname rtspecialname int32 value__
}

What should get your attention here is that the value__ is stored separately from the enum values. In the case of the enum Foo above, the type of value__ is int16. This basically means that you can store whatever you want in an enum, as long as the types match.

At this point I'd like to point out that System.Enum is a value type, which basically means that BarFlag will take up 4 bytes in memory and Foo will take up 2 -- e.g. the size of the underlying type (it's actually more complicated than that, but hey...).

The answer

So, if you have an integer that you want to map to an enum, the runtime only has to do 2 things: copy the 4 bytes and name it something else (the name of the enum). Copying is implicit because the data is stored as value type - this basically means that if you use unmanaged code, you can simply interchange enums and integers without copying data.

To make it safe, I think it's a best practice to know that the underlying types are the same or implicitly convertible and to ensure the enum values exist (they aren't checked by default!).

To see how this works, try the following code:

public enum MyEnum : int
{
    Foo = 1,
    Bar = 2,
    Mek = 5
}

static void Main(string[] args)
{
    var e1 = (MyEnum)5;
    var e2 = (MyEnum)6;

    Console.WriteLine("{0} {1}", e1, e2);
    Console.ReadLine();
}

Note that casting to e2 also works! From the compiler perspective above this makes sense: the value__ field is simply filled with either 5 or 6 and when Console.WriteLine calls ToString(), the name of e1 is resolved while the name of e2 is not.

If that's not what you intended, use Enum.IsDefined(typeof(MyEnum), 6) to check if the value you are casting maps to a defined enum.

Also note that I'm explicit about the underlying type of the enum, even though the compiler actually checks this. I'm doing this to ensure I don't run into any surprises down the road. To see these surprises in action, you can use the following code (actually I've seen this happen a lot in database code):

public enum MyEnum : short
{
    Mek = 5
}

static void Main(string[] args)
{
    var e1 = (MyEnum)32769; // will not compile, out of bounds for a short

    object o = 5;
    var e2 = (MyEnum)o;     // will throw at runtime, because o is of type int

    Console.WriteLine("{0} {1}", e1, e2);
    Console.ReadLine();
}

Solution 5

Take the following example:

int one = 1;
MyEnum e = (MyEnum)one;
Share:
1,764,165
Nathan Kurz
Author by

Nathan Kurz

Co-Founder of KeyPay - Simple, intuitive, cloud-based payroll system for small to medium Australian businesses

Updated on April 01, 2022

Comments

  • Nathan Kurz
    Nathan Kurz about 2 years

    How can an int be cast to an enum in C#?

  • dtroy
    dtroy almost 15 years
    Beware you can't use Enum.IsDefined if you use the Flags attribute and the value is a combination of flags for example: Keys.L | Keys.Control
  • CodesInChaos
    CodesInChaos over 12 years
    That's useful when converting from a string. But not when converting from an int.
  • Tathagat Verma
    Tathagat Verma over 12 years
    That correct it should be: YourEnum foo = (YourEnum) Enum.Parse(typeof(YourEnum), yourString) OR YourEnum foo = (YourEnum) Enum.Parse(typeof(YourEnum), yourInt) -- As applicable.
  • Shimmy Weitzhandler
    Shimmy Weitzhandler about 12 years
    @FlySwat, what if YourEnum is dynamic and will only be known at runtime, and what I want is to convert to Enum?
  • Olivier Jacot-Descombes
    Olivier Jacot-Descombes about 11 years
    @Shimmy. If the enum is only known at runtime, keep it dynamic. Type safety (strong typing) can only be guaranteed by the compiler anyway. You cannot strongly type an object at runtime. The closest you can come to it is by using generics, but the generic type must be known at compile time. T ToEnum<T>(int x) { return (T)x; } but there is no real advantage over casting directly.
  • Logan
    Logan about 11 years
    Quick question, if you were to go back from YourEnum foo to int anInt type: anInt = (int)foo; would that work?
  • Jeppe Stig Nielsen
    Jeppe Stig Nielsen about 11 years
    @Logan Sure, it works. (If the underlying integer type of the enum is not int, cast to that underlying integer type instead. But it is extremely rare that the underlying type should be something else than simply int.)
  • jropella
    jropella about 11 years
    Be aware that Enum.Parse will NOT work if your code is obfuscated. At run time after obfuscation the string is compared to the enum names, and at this point the names of the enums aren't what you would expect them to be. Your parse will fail where they succeeded before as a result.
  • BrainSlugs83
    BrainSlugs83 almost 11 years
    For processing user input, it's probably a good idea to call the overload of Enum.Parse that is allows you to specify that the comparison NOT be case sensitive (i.e. a user typing "red" (lowercase) would crash the above code without this change.)
  • JoeCool
    JoeCool almost 11 years
    BEWARE If you use the "from a string" syntax above and pass in an invalid string that is a number (e.g. "2342342" -- assuming that's not a value of your enum), it will actually allow that without throwing an error! Your enum will have that value (2342342) even though it's not a valid choice in the enum itself.
  • Justin T Conroy
    Justin T Conroy over 10 years
    I think this answer is a bit dated now. For string, you should really be using var result = Enum.TryParse(yourString, out yourEnum) nowadays (and checking the result to determine if the conversion failed).
  • adrian
    adrian over 10 years
    Regarding Enum.IsDefined, be aware that it can be dangerous: msdn.microsoft.com/en-us/library/ms229025(VS.90).aspx
  • jackvsworld
    jackvsworld over 10 years
    @JustinTConroy I don't know if I agree with that. In my programs, if the conversion fails it's often a non-recoverable error, so I want the exception to be thrown.
  • Justin T Conroy
    Justin T Conroy over 10 years
    The Parse function presents a classic example of a vexing exception. That is, an exception that is thrown in a completely non-exceptional circumstance, usually due to an unfortunate design decision. The developers of C# recognized this unfortunate design and later added TryParse to deal with this. TryParse returns a boolean that indicates if the parse succeeded or failed, so you should use that boolean instead of an exception handler. See Eric Lippert's blog post about vexing exceptions for more information.
  • Erik Schierboom
    Erik Schierboom over 10 years
    It is also possible to have Enum.Parse be case-insensitive by adding a true parameter value to the call: YourEnum foo = (YourEnum) Enum.Parse(typeof(YourEnum), yourString, true);
  • Pap
    Pap over 9 years
    I prefer this definition: "Returns an indication whether a constant with a specified value exists in a specified enumeration" from MSDN
  • Pap
    Pap over 9 years
    ...Because your definition can be misleading, because you are saying: "...check if it's in range..." which implies within a range of numbers with starting and ending limits...
  • Paul Richards
    Paul Richards over 9 years
    enums superseded the use of integer constants like this since they provide more type safety
  • Ted
    Ted over 9 years
    Paul, this is a method of collecting together related int constants (e.g. Database id constants) so they can be used directly without having to cast them to int every time they're used. Their type is integer, not for example, DatabaseIdsEnum.
  • Thierry
    Thierry over 9 years
    There is at least one situation that I have found in which enum type safety can be unintentionally bypassed.
  • Santhos
    Santhos over 9 years
    Is it possible that the conversion from int works even if the int value is not present in the enum? I just tried it in .net 3.5 and it seems to work which is quite confusing.
  • Colin
    Colin over 9 years
    Enum.ToObject was what I was looking for. This is exactly what you need when working with enums dynamically and you have a type that you know is an enum but can't prove it to the compiler, which won't allow you to cast from an int value to an arbitrary type.
  • Thaoden
    Thaoden about 9 years
    @Santhos Yes, there is Enum.IsDefined() to check if the value you want to convert exists in your enum.
  • BJury
    BJury almost 9 years
    The question specifically asks about integers.
  • BJury
    BJury almost 9 years
    Handy, but the question specifically asks about ints.
  • Aidiakapi
    Aidiakapi over 8 years
    @JustinTConroy Except that it's not. When you call Parse, you trust the input value to be correct, and when it isn't, it's a bug in the code (and there's an exception as there should be). If you're dealing with user input, you should always call TryParse, because invalid input isn't exceptional. The article you linked mentions this in "the 99% use case for this method is transforming strings input by the user", that's the bug, the method isn't designed to handle user input, TryParse is.
  • Rolan
    Rolan over 8 years
    I realize this is an old post, but how do you gain this level of knowledge in c#? Is this from reading through the C# specification?
  • atlaste
    atlaste over 8 years
    @Rolan I sometimes wish more people would ask that. :-) To be honest I don't really know; I try to understand how things work and get information wherever I can get it. I did read the C# standard, but I also regularly decompile code with Reflector (I even look at the x86 assembler code a lot) and do tons of little experiments. Also, knowing about other languages helps in this case; I've been doing CS for about 30 years now, and at some point certain things become 'logical' - f.ex. an enum should integral types, because otherwise interop will break (or your performance will go down the drain).
  • atlaste
    atlaste over 8 years
    I believe the key to doing software engineering properly is knowing how stuff works. For me that means that if you write a piece of code, you know how it roughly translates to f.ex. processor operations and memory fetches / writes. If you ask how to get to that level, I'd suggest building a ton of small test cases, making them tougher as you go, try to predict the outcome every time, and test them afterwards (incl. decompilation, etc). After figuring out all the details and all the characteristics, you can check if you got it right in the (dull) standard. At least, that would be my approach.
  • orion elenzil
    orion elenzil over 8 years
    this is good. i was surprised there's not an exception when casting an invalid value to an int-backed enum.
  • JeremyWeir
    JeremyWeir about 8 years
    Will Yu please edit your answer to let everyone know Enum.TryParse will work on a string of the value or name of the enum (I couldn't resist)
  • gravidThoughts
    gravidThoughts over 7 years
    Fantastic answer, thanks! In your last code sample, it throws an exception at runtime because o is an object. You can cast an int variable to a short as long as it falls within the short range.
  • atlaste
    atlaste over 7 years
    @gravidThoughts Thanks. Actually it's an unboxing operation, so it won't do any implicit conversions like the ones you describe. Casting is sometimes confusing in C# if you don't know the details... Anyhow, because int != short, it will throw (unboxing fails). If you do object o = (short)5;, it will work, because then the types will match. It's not about the range, it's really about the type.
  • TruthOf42
    TruthOf42 over 7 years
    this also works if the string is an integer, e.g. "2"
  • Justin
    Justin over 7 years
    This will throw an exception if enumString is null (had a similar issue yesterday). Consider using TryParse instead of Parse. TryParse will also check if T is an Enum Type
  • Don Cheadle
    Don Cheadle over 6 years
    This actually is not so different than the top-rated answer. That answer also discusses using Enum.IsDefined after you've casted the string to the Enum type. So even if the string was casted without error, Enum.IsDefined will still catch it
  • daniloquio
    daniloquio about 6 years
    Note that an Enum's value is int by default, but that can be changed which may make the cast dangerous. Check @atlastes's answer.
  • crenshaw-dev
    crenshaw-dev over 5 years
    @adrian can you provide a succinct example of a dangerous scenario? Having trouble wrapping my head around that doc.
  • Scott
    Scott over 5 years
    This can now be improved with C# 7.3 by constraining to Enum instead of struct, meaning we don't have to rely on the runtime check!
  • adrian
    adrian over 5 years
    @mac9416 I've tried to give a succinct example at gist.github.com/alowdon/f7354cda97bac70b44e1c04bc0991bcc - basically by using IsDefined to check input values, you leave yourself vulnerable to people adding new enum values later which would pass an IsDefined check (since the new value exists in the new code), but which might not work with the original code you wrote. It's therefore safer to explicitly specify the enum values that your code is able to handle.
  • Mr Anderson
    Mr Anderson almost 5 years
    This type of extension method on System.String seems like namespace pollution
  • derHugo
    derHugo over 4 years
    But enums also make sure the values are all unique, something this approach is also lacking
  • Jimi
    Jimi over 4 years
    In latest C#/.NET you can use E instead of T so you are sure that the method gets called on an Enum class
  • MikeBeaton
    MikeBeaton about 4 years
    This is a nice answer. It's a shame it's so far down the page at the moment!
  • qwerty
    qwerty almost 4 years
    If the cast worked, you wouldn't be able to store it as an int.
  • Inam Abbas
    Inam Abbas almost 4 years
    Please try to understand int to Enum I think is above answer to help you.
  • Ε Г И І И О
    Ε Г И І И О over 3 years
    You return default(T) when it's not defined. How is that helping to identify the undefined ones?
  • NDUF
    NDUF over 3 years
    this is actually much better because if the int value is not a defined entry in the enum, you can use a else statement to set enumString to a default value. Thanks
  • belka
    belka over 2 years
    works in case of a string not an int for example
  • Shah Zain
    Shah Zain about 2 years
    Added case for int.