104

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?

orj
  • 13,234
  • 14
  • 63
  • 73
  • 1
    I believe it's compiler that is complaining, not Resharper. – Kugel Aug 28 '12 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. – Mir Mar 03 '14 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. – akousmata Oct 27 '15 at 16:15

9 Answers9

156

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

Hannele
  • 9,301
  • 6
  • 48
  • 68
MartinStettner
  • 28,719
  • 15
  • 79
  • 106
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));
    }
BFree
  • 102,548
  • 21
  • 159
  • 201
  • I gave you +1 but this solution is going to work only with C# 3.0 and higher. – Vadim May 26 '09 at 01:41
  • I think, this only satisfies the compiler. Did you manage to test this at runtime? I could not pass any value to this function... – MartinStettner May 26 '09 at 01:43
  • Because it's an extension method? Or is something different about enums in older versions of C#? – BFree May 26 '09 at 01:43
  • I added a test to the end of my post. I tried that and it worked for me. – BFree May 26 '09 at 01:44
  • @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) – MartinStettner May 26 '09 at 01:49
  • If you want a real challenge, try going the opposite direction, from a generic type parameter TEnum to an int. Good luck! – Triynko May 15 '18 at 22:15
16

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()));
Drew Noakes
  • 300,895
  • 165
  • 679
  • 742
  • 5
    This is the only bulletproof answer. – Rudey Mar 03 '16 at 15:53
  • Is this cause boxing unboxing? – kitta Jul 07 '18 at 07:01
  • @b.ben yes. [`Convert.ChangeType`](https://learn.microsoft.com/en-us/dotnet/api/system.convert.changetype?view=netframework-4.7.1#System_Convert_ChangeType_System_Object_System_Type_) accepts `object` for the first argument, and returns `object`. – Drew Noakes Jul 07 '18 at 11:11
  • 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. – Twenty Dec 24 '19 at 00:26
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();
LukeH
  • 263,068
  • 57
  • 365
  • 409
  • 6
    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 May 27 '09 at 01:03
  • @orj, I'm not really sure what you mean. Can you give an example showing the usage you need? – LukeH May 27 '09 at 08:59
  • 2
    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. – Daniel T. Feb 02 '10 at 03:38
  • 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. – Louise Eggleton Jan 17 '18 at 17:27
  • 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 – Louise Eggleton Jan 17 '18 at 17:34
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();
Community
  • 1
  • 1
nawfal
  • 70,104
  • 56
  • 326
  • 368
  • Are you sure the second one is faster? I assume it will box the enum and then unbox back to int? – yoyo Jul 12 '14 at 23:24
  • 1
    @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](http://stackoverflow.com/questions/7995606/boxing-occurrence-in-c-sharp) – nawfal Jul 13 '14 at 02:04
  • thanks for the explanation. I was under the mistaken impression that an instance of System.Enum was an unboxed value. See this too -- http://msdn.microsoft.com/en-us/library/aa691158(v=vs.71).aspx – yoyo Jul 13 '14 at 04:28
  • @yoyo hmm yes. The relevant quote from the link: *From any enum-type to the type System.Enum.* – nawfal Jul 13 '14 at 06:59
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);
  }
}
eisenpony
  • 565
  • 4
  • 10
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.

jpoh
  • 4,536
  • 4
  • 35
  • 60
0

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

Dwedit
  • 618
  • 5
  • 11
-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);
Michael Kniskern
  • 24,792
  • 68
  • 164
  • 231
jrista
  • 32,447
  • 15
  • 90
  • 130
  • 1
    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 – Vadim May 26 '09 at 01:54
  • 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.) – jrista May 26 '09 at 04:36
  • you can use: if (!typeof(E).IsEnum) throw new ArgumentException("E must be an enumerated type"); – diadiora Jul 03 '10 at 17:39
  • 1
    This isn't even remotely correct, the static helper is not even valid. – Nicholi Jun 29 '13 at 03:55
  • 1
    Why should someone use `EnumHelpers.Convert(StopLight.Red);` instead of `(int)StopLight.Read;`? Also the question is talking about `System.Enum`. – nawfal Dec 01 '13 at 12:12