105

I'd like to create a generic method for converting any System.Enum derived type to its corresponding integer value, without casting and preferably without parsing a string.

Eg, what I want is something like this:

// Trivial example, not actually what I'm doing.
class Converter
{
    int ToInteger(System.Enum anEnum)
    {
        (int)anEnum;
    }
}

But this doesn't appear to work. Resharper reports that you can not cast expression of type 'System.Enum' to type 'int'.

Now I've come up with this solution but I'd rather have something more efficient.

class Converter
{
    int ToInteger(System.Enum anEnum)
    {
        return int.Parse(anEnum.ToString("d"));
    }
}

Any suggestions?

3
  • 1
    I believe it's compiler that is complaining, not Resharper. Commented Aug 28, 2012 at 11:25
  • 1
    Not necessarily. I have an extension method on System.Enum, and occasionally Resharper decides to complain: Cannot convert instance argument type 'Some.Cool.Type.That.Is.An.Enum' to 'System.Enum' when it unquestionably IS an enum. If I compile and run the code it works just fine. If I then shut down VS, blow away the Resharper cache, and fire it back up, everything is fine once its done rescanning. For me it's some kind of cache snafu. Might be the same for him. Commented Mar 3, 2014 at 22:12
  • @Mir I've had ReSharper "complain" on this as well. Same fix for me. Not sure why it gets these types mixed up, but it is definitely not the compiler. Commented Oct 27, 2015 at 16:15

9 Answers 9

159

If you don't want to cast,

Convert.ToInt32()

could do the trick.

The direct cast (via (int)enumValue) is not possible. Note that this would also be "dangerous" since an enum can have different underlying types (int, long, byte...).

More formally: System.Enum has no direct inheritance relationship with Int32 (though both are ValueTypes), so the explicit cast cannot be correct within the type system

Sign up to request clarification or add additional context in comments.

5 Comments

Converter.ToInteger(MyEnum.MyEnumConstant); will give you no error here. Please edit that part.
THanks, @nawfal, you're right. I edited the response (and learned something new :) ...)
Is not working if underlying type differs from int
@YaroslavSivakov it won't work e.g. for long enum.
System.Enum is a class, so it is a reference type. Values are probably boxed.
49

I got it to work by casting to an object and then to an int:

public static class EnumExtensions
{
    public static int ToInt(this Enum enumValue)
    {
        return (int)((object)enumValue);
    }
}

This is ugly and probably not the best way. I'll keep messing with it, to see if I can come up with something better....

EDIT: Was just about to post that Convert.ToInt32(enumValue) works as well, and noticed that MartinStettner beat me to it.

public static class EnumExtensions
{
    public static int ToInt(this Enum enumValue)
    {
        return Convert.ToInt32(enumValue);
    }
}

Test:

int x = DayOfWeek.Friday.ToInt();
Console.WriteLine(x); // results in 5 which is int value of Friday

EDIT 2: In the comments, someone said that this only works in C# 3.0. I just tested this in VS2005 like this and it worked:

public static class Helpers
{
    public static int ToInt(Enum enumValue)
    {
        return Convert.ToInt32(enumValue);
    }
}

    static void Main(string[] args)
    {
        Console.WriteLine(Helpers.ToInt(DayOfWeek.Friday));
    }

6 Comments

I gave you +1 but this solution is going to work only with C# 3.0 and higher.
I think, this only satisfies the compiler. Did you manage to test this at runtime? I could not pass any value to this function...
Because it's an extension method? Or is something different about enums in older versions of C#?
I added a test to the end of my post. I tried that and it worked for me.
@BFree: It seems only to work with extension methods. I tried it with an "old-style" function (in C# 2.0) and didn't manage to find the syntax to actually pass any value to it (that's what my previous comment was about)
|
17

If you need to convert any enum to its underlying type (not all enums are backed by int) then you can use:

return System.Convert.ChangeType(
    enumValue,
    Enum.GetUnderlyingType(enumValue.GetType()));

4 Comments

This is the only bulletproof answer.
Is this cause boxing unboxing?
@b.ben yes. Convert.ChangeType accepts object for the first argument, and returns object.
Yea I do actually agree with @Rudey on this, anyhow you should do performance tests. BFree's solution is by far the quickest. About eight times faster. Anyway we are still talking about ticks.
9

Why do you need to reinvent the wheel with a helper method? It's perfectly legal to cast an enum value to its underlying type.

It's less typing, and in my opinion more readable, to use...

int x = (int)DayOfWeek.Tuesday;

...rather than something like...

int y = Converter.ToInteger(DayOfWeek.Tuesday);
// or
int z = DayOfWeek.Tuesday.ToInteger();

5 Comments

I want to convert ANY enum value. Ie, I have a variety of classes that have enum fields that are being processed by some code in a generic way. This is why a simple cast to int is not appropriate.
@orj, I'm not really sure what you mean. Can you give an example showing the usage you need?
Sometimes you can't directly cast an enum, such as in the case of a generic method. Because generic methods can't be constrained to enums, you have constrain it to something like struct, which can't be cast into an int. In that case, you can use Convert.ToInt32(enum) to do it.
I like the idea that the extension method ToInteger() follows the same format as ToString(). I think it is less readable to cast to int on one hand when you want the int value and use ToString() when we need the string value especially when the code is side by side.
Also, using an extension method can add consistency to your code base. Since, as @nawfal pointed, out there are several ways that you can get the int value from an enum, creating an extension method and enforcing its use means that your every time you get the int value of an enum you are using the same method
4

From my answer here:

Given e as in:

Enum e = Question.Role;

Then these work:

int i = Convert.ToInt32(e);
int i = (int)(object)e;
int i = (int)Enum.Parse(e.GetType(), e.ToString());
int i = (int)Enum.ToObject(e.GetType(), e);

The last two are plain ugly. The first one should be more readable, though the second one is much faster. Or may be an extension method is the best, best of both worlds.

public static int GetIntValue(this Enum e)
{
    return e.GetValue<int>();
}

public static T GetValue<T>(this Enum e) where T : struct, IComparable, IFormattable, IConvertible, IComparable<T>, IEquatable<T>
{
    return (T)(object)e;
}

Now you can call:

e.GetValue<int>(); //or
e.GetIntValue();

4 Comments

Are you sure the second one is faster? I assume it will box the enum and then unbox back to int?
@yoyo the e variable already has the boxed instance of actual value type, ie, enum. When you write Enum e = Question.Role; it's already boxed. The question is about converting the boxed System.Enum back to underlying int type (unboxing). So here unboxing is only the performance concern. (int)(object)e is a direct unbox call; yes should be faster than other approaches. See this
thanks for the explanation. I was under the mistaken impression that an instance of System.Enum was an unboxed value. See this too -- msdn.microsoft.com/en-us/library/aa691158(v=vs.71).aspx
@yoyo hmm yes. The relevant quote from the link: From any enum-type to the type System.Enum.
1

Casting from a System.Enum to an int works fine for me (it's also on the MSDN). Perhaps it's a Resharper bug.

3 Comments

What version of the runtime you using?
the link shows casting of sub types of System.Enum, not System.Enum itself.
A similar problem I had was a Resharper cache snafu. Closing VS and deleting the Resharper cache made the error disappear, even after full rescan.
1

Since Enums are restricted to byte, sbyte, short, ushort, int, uint, long and ulong, we can make some assumptions.

We can avoid exceptions during conversion by using the largest available container. Unfortunately, which container to use is not clear because ulong will blow up for negative numbers and long will blow up for numbers between long.MaxValue and ulong.MaxValue. We need to switch between these choices based on the underlying type.

Of course, you still need to decide what to do when the result doesn't fit inside an int. I think casting is okay, but there are still some gotchas:

  1. for enums based on a type with a field space larger than int (long and ulong), it's possible some enums will evaluate to the same value.
  2. casting a number larger than int.MaxValue will throw an exception if you are in a checked region.

Here's my suggestion, I'll leave it to the reader to decide where to expose this function; as a helper or an extension.

public int ToInt(Enum e)
{
  unchecked
  {
    if (e.GetTypeCode() == TypeCode.UInt64)
      return (int)Convert.ToUInt64(e);
    else
      return (int)Convert.ToInt64(e);
  }
}

Comments

0

If you read the code for Convert.ToInt32, you can see that it casts the Enum to IConvertible, then calls ToInt32(null).

Comments

-1

Don't forget that the Enum type itself has a bunch of static helper functions in it. If all you want to do is convert an instance of the enum to its corresponding integer type, then casting is probably the most efficient way.

I think ReSharper is complaining because Enum isn't an enumeration of any particular type, and enumerations themselves derive from a scalar valuetype, not Enum. If you need adaptable casting in a generic way, I would say this could suite you well (note that the enumeration type itself is also included in the generic:

public static EnumHelpers
{
    public static T Convert<T, E>(E enumValue)
    {
        return (T)enumValue;
    }
}

This could then be used like so:

public enum StopLight: int
{
    Red = 1,
    Yellow = 2,
    Green = 3
}

// ...

int myStoplightColor = EnumHelpers.Convert<int, StopLight>(StopLight.Red);

I can't say for sure off the top of my head, but the above code might even be supported by C#'s type inference, allowing the following:

int myStoplightColor = EnumHelpers.Convert<int>(StopLight.Red);

5 Comments

Unfortunately, in your example E can be any type. Generics don't allow me to use Enum as type parameter constraint. I cannot say: where T : Enum
You could use where T: struct, though. Its not quite as strict as you want it to be, but it would cut out any reference type (which I think is what your trying to do.)
you can use: if (!typeof(E).IsEnum) throw new ArgumentException("E must be an enumerated type");
This isn't even remotely correct, the static helper is not even valid.
Why should someone use EnumHelpers.Convert<int, StopLight>(StopLight.Red); instead of (int)StopLight.Read;? Also the question is talking about System.Enum.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.