How can I cast int to enum?
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;
Nathan Kurz
Co-Founder of KeyPay - Simple, intuitive, cloud-based payroll system for small to medium Australian businesses
Updated on April 01, 2022Comments
-
Nathan Kurz about 2 years
How can an
int
be cast to anenum
in C#? -
dtroy almost 15 yearsBeware 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 over 12 yearsThat's useful when converting from a string. But not when converting from an int.
-
Tathagat Verma over 12 yearsThat 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 about 12 years@FlySwat, what if
YourEnum
is dynamic and will only be known at runtime, and what I want is to convert toEnum
? -
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 about 11 yearsQuick question, if you were to go back from
YourEnum foo
toint anInt
type:anInt = (int)foo;
would that work? -
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 simplyint
.) -
jropella about 11 yearsBe 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 almost 11 yearsFor 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 almost 11 yearsBEWARE 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 over 10 yearsI 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 over 10 yearsRegarding
Enum.IsDefined
, be aware that it can be dangerous: msdn.microsoft.com/en-us/library/ms229025(VS.90).aspx -
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 over 10 yearsThe 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 over 10 yearsIt is also possible to have
Enum.Parse
be case-insensitive by adding atrue
parameter value to the call:YourEnum foo = (YourEnum) Enum.Parse(typeof(YourEnum), yourString, true);
-
Pap over 9 yearsI prefer this definition: "Returns an indication whether a constant with a specified value exists in a specified enumeration" from MSDN
-
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 over 9 yearsenums superseded the use of integer constants like this since they provide more type safety
-
Ted over 9 yearsPaul, 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 over 9 yearsThere is at least one situation that I have found in which enum type safety can be unintentionally bypassed.
-
Santhos over 9 yearsIs 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 over 9 yearsEnum.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 about 9 years@Santhos Yes, there is
Enum.IsDefined()
to check if the value you want to convert exists in your enum. -
BJury almost 9 yearsThe question specifically asks about integers.
-
BJury almost 9 yearsHandy, but the question specifically asks about ints.
-
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 callTryParse
, 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 over 8 yearsI 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 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 over 8 yearsI 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 over 8 yearsthis is good. i was surprised there's not an exception when casting an invalid value to an int-backed enum.
-
JeremyWeir about 8 yearsWill 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 over 7 yearsFantastic 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 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 doobject 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 over 7 yearsthis also works if the string is an integer, e.g. "2"
-
Justin over 7 yearsThis 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 over 6 yearsThis 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 about 6 yearsNote 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 over 5 years@adrian can you provide a succinct example of a dangerous scenario? Having trouble wrapping my head around that doc.
-
Scott over 5 yearsThis can now be improved with C# 7.3 by constraining to
Enum
instead ofstruct
, meaning we don't have to rely on the runtime check! -
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 anIsDefined
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 almost 5 yearsThis type of extension method on
System.String
seems like namespace pollution -
derHugo over 4 yearsBut enums also make sure the values are all unique, something this approach is also lacking
-
Jimi over 4 yearsIn latest C#/.NET you can use
E
instead ofT
so you are sure that the method gets called on an Enum class -
MikeBeaton about 4 yearsThis is a nice answer. It's a shame it's so far down the page at the moment!
-
qwerty almost 4 yearsIf the cast worked, you wouldn't be able to store it as an int.
-
Inam Abbas almost 4 yearsPlease try to understand int to Enum I think is above answer to help you.
-
Ε Г И І И О over 3 yearsYou return default(T) when it's not defined. How is that helping to identify the undefined ones?
-
NDUF over 3 yearsthis 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 over 2 yearsworks in case of a string not an int for example
-
Shah Zain about 2 yearsAdded case for int.