11
\$\begingroup\$

As you know, converting an int to an enum is straightforward. Doing it generically with type/range checking isn't. I looked for a reusable example since this seems like a common situation but did not find a suitable one. If it exists, please let me know. Below is a C# extension method that encapsulates this behavior. Any feedback is welcome.

public static T ToEnum<T>(this int value)
{
    Type type = typeof(T);

    if (!type.IsEnum)
    {
        throw new ArgumentException($"{type} is not an enum.");
    }

    if (!type.IsEnumDefined(value))
    {
        throw new ArgumentException($"{value} is not a valid ordinal of type {type}.");
    }

    return (T)Enum.ToObject(type, value);
}
\$\endgroup\$
4
  • 4
    \$\begingroup\$ Be careful withIsEnumDefined. It won't work if using Flagsand the value represents a combination. \$\endgroup\$ Commented Aug 16, 2018 at 13:24
  • \$\begingroup\$ @JasonTyler Correct. It may not work as expected in some cases. It does return the enum containing combined flags. Not sure what the use case is for getting the combined flags and converting them from their ordinals back to flags. \$\endgroup\$ Commented Aug 16, 2018 at 14:13
  • 1
    \$\begingroup\$ where T : struct could use a generic constraint. \$\endgroup\$ Commented Aug 16, 2018 at 14:27
  • \$\begingroup\$ where T : enum could be used as a constraint now. \$\endgroup\$
    – user34073
    Commented Nov 12, 2018 at 18:15

3 Answers 3

13
\$\begingroup\$

As Jason Tyler said in a comment, this has a problem that [Flags] enumerations won't be properly handled.

I ran this in C# interactive, and it threw an exception (as expected, but not desired) for a valid [Flags] value:

> public static T ToEnum<T>(this int value)
. {
.     Type type = typeof(T);
. 
.     if (!type.IsEnum)
.     {
.         throw new ArgumentException($"{type} is not an enum.");
. 
.     }
. 
.     if (!type.IsEnumDefined(value))
.     {
.         throw new ArgumentException($"{value} is not a valid ordinal of type {type}.");
.     }
. 
.     return (T)Enum.ToObject(type, value);
. }
> [Flags] public enum Test { Flag1 = 0x01, Flag2 = 0x02 }
> ToEnum<Test>(3);
3 is not a valid ordinal of type Submission#1+Test.
  + Submission#0.ToEnum<T>(int)

So, we might have to look at a different way of going about this.

There's an answer on Stack Overflow, but I don't like it. They use string comparison and validation, and it just feels like a hack.

So what can we do?

Well, we have Enum.GetValues, I bet we can come up with a solution there, assuming we interpret all the values as a numeric type.

The hard part is picking the type. Enums can be any numeric type, so we have to decide on one.

Fun fact: every numeric type can be cast to the others in C#, there just might be overflow issues. So if we look at all the numeric types, we can find that we should always be able to cast them to a long or ulong, depending on whether they're signed or not.

OK, so how do we figure out what number type it is?

There's another magic function in Enum: Enum.GetUnderlyingType, I think that'll do.

Of course, this also means we can no longer take an int input, because we want to support any number. We could take in an object, but then we have to deal with boxing/unboxing, and that can get prohibitively expensive with frequent use, but we'll work that out-of-the-way later.

We can use some bit-fiddling to find out if a value is only composed of valid Enum values. Basically, we'll do the following:

  • Loop through the valid flags options:
    • If providedValue ∧ enumValue > 0, then providedValue = providedValue ⊕ enumValue
  • If providedValue > 0 then it is not composed strictly of the valid enum options

For those unfamiliar with boolean algebra:

  • = "AND", take all bits of both values and compare them such that the result value only contains those that are 1 in each value, this is & in C#;
  • = "XOR", take all bits of both values and compare them such that the result value only contains those that are 1 in one value, and 0 in another, this is ^ in C#;

So, if we rewrite this, it gets a bit ugly, but we'll clean some of that up:

public static TEnum ToEnum<TEnum>(this object value)
{
    Type type = typeof(TEnum);

    if (!type.IsEnum)
    {
        throw new ArgumentException($"{type} is not an enum.");
    }

    if (type.GetCustomAttributes(typeof(FlagsAttribute), true).Length > 0)
    {
        var values = Enum.GetValues(type);
        switch (Enum.GetUnderlyingType(type).FullName)
        {
            case "System.Byte":
                {
                    var myVal = (byte)value;
                    foreach (byte val in values)
                    {
                        if ((myVal & val) > (byte)0)
                        {
                            myVal ^= val;
                        }
                    }
                    if (myVal > (byte)0)
                    {
                        throw new ArgumentException($"{value} is not a valid ordinal of type {type}.");
                    }
                }
                break;
            case "System.SByte":
                {
                    var myVal = (sbyte)value;
                    foreach (sbyte val in values)
                    {
                        if ((myVal & val) > (sbyte)0)
                        {
                            myVal ^= val;
                        }
                    }
                    if (myVal > (sbyte)0)
                    {
                        throw new ArgumentException($"{value} is not a valid ordinal of type {type}.");
                    }
                }
                break;
            case "System.UInt16":
                {
                    var myVal = (ushort)value;
                    foreach (ushort val in values)
                    {
                        if ((myVal & val) > (ushort)0)
                        {
                            myVal ^= val;
                        }
                    }
                    if (myVal > (ushort)0)
                    {
                        throw new ArgumentException($"{value} is not a valid ordinal of type {type}.");
                    }
                }
                break;
            case "System.Int16":
                {
                    var myVal = (short)value;
                    foreach (short val in values)
                    {
                        if ((myVal & val) > (short)0)
                        {
                            myVal ^= val;
                        }
                    }
                    if (myVal > (short)0)
                    {
                        throw new ArgumentException($"{value} is not a valid ordinal of type {type}.");
                    }
                }
                break;
            case "System.UInt32":
                {
                    var myVal = (uint)value;
                    foreach (uint val in values)
                    {
                        if ((myVal & val) > (uint)0)
                        {
                            myVal ^= val;
                        }
                    }
                    if (myVal > (uint)0)
                    {
                        throw new ArgumentException($"{value} is not a valid ordinal of type {type}.");
                    }
                }
                break;
            case "System.Int32":
                {
                    var myVal = (int)value;
                    foreach (int val in values)
                    {
                        if ((myVal & val) > (int)0)
                        {
                            myVal ^= val;
                        }
                    }
                    if (myVal > (int)0)
                    {
                        throw new ArgumentException($"{value} is not a valid ordinal of type {type}.");
                    }
                }
                break;
            case "System.UInt64":
                {
                    var myVal = (ulong)value;
                    foreach (ulong val in values)
                    {
                        if ((myVal & val) > (ulong)0)
                        {
                            myVal ^= val;
                        }
                    }
                    if (myVal > (ulong)0)
                    {
                        throw new ArgumentException($"{value} is not a valid ordinal of type {type}.");
                    }
                }
                break;
            case "System.Int64":
                {
                    var myVal = (long)value;
                    foreach (long val in values)
                    {
                        if ((myVal & val) > (long)0)
                        {
                            myVal ^= val;
                        }
                    }
                    if (myVal > (long)0)
                    {
                        throw new ArgumentException($"{value} is not a valid ordinal of type {type}.");
                    }
                }
                break;
            default:
                throw new ArgumentException($"{type} does not have a valid backing type ({underlyingType}).");
                break;
        }
    }
    else
    {
        if (!type.IsEnumDefined(value))
        {
            throw new ArgumentException($"{value} is not a valid ordinal of type {type}.");
        }
    }

    return (TEnum)Enum.ToObject(type, value);
}

This will work as expected on [Flags] enumerations, which is great! But, there's some improvement to be made.

First and foremost: how do we get rid of that object parameter?

Well, we have a few options, but the easiest is to redefine our ToEnum on each numeric type, and create a version that takes a dynamic. It's ugly, but works:

public static TEnum ToEnum<TEnum>(this byte value) => DynamicToEnum<TEnum>(value);
public static TEnum ToEnum<TEnum>(this sbyte value) => DynamicToEnum<TEnum>(value);
public static TEnum ToEnum<TEnum>(this ushort value) => DynamicToEnum<TEnum>(value);
public static TEnum ToEnum<TEnum>(this short value) => DynamicToEnum<TEnum>(value);
public static TEnum ToEnum<TEnum>(this uint value) => DynamicToEnum<TEnum>(value);
public static TEnum ToEnum<TEnum>(this int value) => DynamicToEnum<TEnum>(value);
public static TEnum ToEnum<TEnum>(this ulong value) => DynamicToEnum<TEnum>(value);
public static TEnum ToEnum<TEnum>(this long value) => DynamicToEnum<TEnum>(value);

private static TEnum DynamicToEnum<TEnum>(dynamic value)
{
    ...

For each repeated case body, there's no good way to do this. With the use dynamic, we lose all safety of our types. There's no way to constrain it generically, because we can't say "it can be any number."

The best we could do would be a local function something like the following:

void testEnum<T>(T myVal, Func<T, bool> aboveZero, Func<T, T, T> and, Func<T, T, T> xor)
{
    foreach (T val in values)
    {
        if (aboveZero(and(myVal, val)))
        {
            myVal = xor(myVal, val);
        }
    }
    if (aboveZero(myVal))
    {
        throw new ArgumentException($"{value} is not a valid ordinal of type {type}.");
    }
}

Which means, we can use it to create a more readable version of our function:

public static TEnum ToEnum<TEnum>(this byte value) => DynamicToEnum<TEnum>(value);
public static TEnum ToEnum<TEnum>(this sbyte value) => DynamicToEnum<TEnum>(value);
public static TEnum ToEnum<TEnum>(this ushort value) => DynamicToEnum<TEnum>(value);
public static TEnum ToEnum<TEnum>(this short value) => DynamicToEnum<TEnum>(value);
public static TEnum ToEnum<TEnum>(this uint value) => DynamicToEnum<TEnum>(value);
public static TEnum ToEnum<TEnum>(this int value) => DynamicToEnum<TEnum>(value);
public static TEnum ToEnum<TEnum>(this ulong value) => DynamicToEnum<TEnum>(value);
public static TEnum ToEnum<TEnum>(this long value) => DynamicToEnum<TEnum>(value);

private static TEnum DynamicToEnum<TEnum>(dynamic value)
{
    Type type = typeof(TEnum);

    if (!type.IsEnum)
    {
        throw new ArgumentException($"{type} is not an enum.");
    }

    if (type.GetCustomAttributes(typeof(FlagsAttribute), true).Length > 0)
    {
        var values = Enum.GetValues(type);

        void testEnum<T>(T myVal, Func<T, bool> aboveZero, Func<T, T, T> and, Func<T, T, T> xor)
        {
            foreach (T val in values)
            {
                if (aboveZero(and(myVal, val)))
                {
                    myVal = xor(myVal, val);
                }
            }
            if (aboveZero(myVal))
            {
                throw new ArgumentException($"{value} is not a valid ordinal of type {type}.");
            }
        }

        var underlyingType = Enum.GetUnderlyingType(type).FullName;
        switch (underlyingType)
        {
            case "System.Byte":
                testEnum((Byte)value, (v) => v > (Byte)0, (v1, v2) => (Byte)(v1 & v2), (v1, v2) => (Byte)(v1 ^ v2));
                break;
            case "System.SByte":
                testEnum((SByte)value, (v) => v > (SByte)0, (v1, v2) => (SByte)(v1 & v2), (v1, v2) => (SByte)(v1 ^ v2));
                break;
            case "System.UInt16":
                testEnum((UInt16)value, (v) => v > (UInt16)0, (v1, v2) => (UInt16)(v1 & v2), (v1, v2) => (UInt16)(v1 ^ v2));
                break;
            case "System.Int16":
                testEnum((Int16)value, (v) => v > (Int16)0, (v1, v2) => (Int16)(v1 & v2), (v1, v2) => (Int16)(v1 ^ v2));
                break;
            case "System.UInt32":
                testEnum((UInt32)value, (v) => v > (UInt32)0, (v1, v2) => (UInt32)(v1 & v2), (v1, v2) => (UInt32)(v1 ^ v2));
                break;
            case "System.Int32":
                testEnum((Int32)value, (v) => v > (Int32)0, (v1, v2) => (Int32)(v1 & v2), (v1, v2) => (Int32)(v1 ^ v2));
                break;
            case "System.UInt64":
                testEnum((UInt64)value, (v) => v > (UInt64)0, (v1, v2) => (UInt64)(v1 & v2), (v1, v2) => (UInt64)(v1 ^ v2));
                break;
            case "System.Int64":
                testEnum((Int64)value, (v) => v > (Int64)0, (v1, v2) => (Int64)(v1 & v2), (v1, v2) => (Int64)(v1 ^ v2));
                break;
            default:
                throw new ArgumentException($"{type} does not have a valid backing type ({underlyingType}).");
                break;
        }
    }
    else
    {
        if (!type.IsEnumDefined(value))
        {
            throw new ArgumentException($"{value} is not a valid ordinal of type {type}.");
        }
    }

    return (TEnum)Enum.ToObject(type, value);
}

Overboard? Probably. But does it work? Oh yeah.

Additionally, as Peter Taylor mentions, you can use where TEnum : struct to help reduce some of the run-time issues, and bring them to the compile-type.

\$\endgroup\$
7
  • \$\begingroup\$ This needs to be compared with the built-in API - I don't trust it ;-) I bet you're already doing this... \$\endgroup\$
    – t3chb0t
    Commented Aug 16, 2018 at 14:58
  • \$\begingroup\$ @t3chb0t I've tested it on everything, assuming one wants to guarantee that the value is only a list of the appropriate flags, then it works just fine. \$\endgroup\$ Commented Aug 16, 2018 at 14:59
  • \$\begingroup\$ I mean performance-wise... there are a lot of loops involeved so I'm very sceptical about them being faster then unboxing. \$\endgroup\$
    – t3chb0t
    Commented Aug 16, 2018 at 15:01
  • \$\begingroup\$ The only performance item I mention is the use of dynamic vs. object, feel free to verify but I'm 99% sure dynamic is faster. (I've used it in production for that exact reason.) \$\endgroup\$ Commented Aug 16, 2018 at 15:03
  • \$\begingroup\$ @202_accepted: I know this is maybe theoretical, but if a flagged enum has negative values the xor-mechanism doesn't work properly. It is unwise to use flags with negative values, but it is possible... \$\endgroup\$
    – user73941
    Commented Aug 17, 2018 at 8:44
9
\$\begingroup\$
public static T ToEnum<T>(this int value)
{
    Type type = typeof(T);

    if (!type.IsEnum)
    {
        throw new ArgumentException($"{type} is not an enum.");
    }

You haven't said anything specific about which version of C# you're using, so I'm going to address two cases.

If you're able to be at the cutting edge and use C# v7.3 then you can simplify this to

public static T ToEnum<T>(this int value)
    where T : Enum
{
    Type type = typeof(T);

If for whatever reason you're forced to use an earlier version of C# you can still at least detect some problems at compile-time with

public static T ToEnum<T>(this int value)
    where T : struct
{
    Type type = typeof(T);

    if (!type.IsEnum)
    {
        throw new ArgumentException($"{type} is not an enum.");
    }

Note that it is a matter of preference or local style whether in 7.3 you combine both tests: the only subtype of Enum which isn't a struct is Enum itself, so the gain is minor.


Depending on your use case, this might not be a problem, but enums aren't necessarily ints. In particular, the following is legal:

enum Foo : long
{
    Bar = 0x1234567890
}

So you might need to use a wider type for value.

\$\endgroup\$
3
  • \$\begingroup\$ A small sidenote: don't trust ReSharper with that where T : Enum, it doesn't understand it until today's update :-o \$\endgroup\$
    – t3chb0t
    Commented Aug 16, 2018 at 14:47
  • \$\begingroup\$ The code uses .NET Core 2.1. The where T : Enum/struct syntax is cleaner if I could use #if defined to compile based on language version. Interesting idea. Researching it right now. \$\endgroup\$ Commented Aug 16, 2018 at 14:52
  • \$\begingroup\$ @user1424660, .Net Core 2.1 is largely orthogonal to the version of the language. I'm using where T : Enum in a Net Standard 1.3 library. It just requires editing the csproj to add a property <LangVersion>7.3</LangVersion>, and having a recent update of VS. \$\endgroup\$ Commented Aug 16, 2018 at 15:03
-1
\$\begingroup\$

I needed a similar solution but I couldn't find anything that was very performant. Ideally Microsoft should have an Enum.Parse(ReadOnlySpan span) and I saw in their dotnet 5 documentation that they had planned it but removed it. My version seems to be the best performing. Please submit others if you have them.

MS Cached Documentation

Method Mean Error StdDev Median Ratio RatioSD Gen 0 Allocated
ToEnum 412.51 ns 24.240 ns 71.47 ns 436.49 ns 1.00 0.00 0.0229 48 B
ToEnumExtensive 3,368.37 ns 236.200 ns 696.44 ns 3,366.78 ns 8.39 2.18 0.1144 240 B
ToEnumDynamic 3,400.10 ns 223.124 ns 657.88 ns 3,471.48 ns 8.48 2.22 0.1450 312 B
ToEnumViaString 74.81 ns 5.526 ns 16.29 ns 71.13 ns 0.19 0.05 - -

Test Harness

 [MemoryDiagnoser]
    public class EnumTest
    {
        [Benchmark(Baseline = true)]
        public void ToEnum()
        {
            var thursday = 4.ToEnum<DayOfWeek>();
            if (thursday != DayOfWeek.Thursday)
                throw new Exception("Failed To Parse");
        }

        [Benchmark(Baseline = false)]
        public void ToEnumExtensive()
        {
            var thursday = 4.ToEnumExtensive<DayOfWeek>();
            if (thursday != DayOfWeek.Thursday)
                throw new Exception("Failed To Parse");
        }
        [Benchmark(Baseline = false)]
        public void ToEnumDynamic()
        {
            var thursday = EnumExtensions.ToEnumDynamic<DayOfWeek>(4);
            if (thursday != DayOfWeek.Thursday)
                throw new Exception("Failed To Parse");
        }
        [Benchmark(Baseline = false)]
        public void ToEnumViaString()
        {
            var thursday = 4.ToEnumViaString<DayOfWeek>();
            if (thursday != DayOfWeek.Thursday)
                throw new Exception("Failed To Parse");
        }
    }

Extension Methods

 public static class EnumExtensions
    {
        public static T ToEnum<T>(this int value)
        {
            Type type = typeof(T);

            if (!type.IsEnum)
            {
                throw new ArgumentException($"{type} is not an enum.");
            }

            if (!type.IsEnumDefined(value))
            {
                throw new ArgumentException($"{value} is not a valid ordinal of type {type}.");
            }

            return (T)Enum.ToObject(type, value);
        }
        public static T ToEnumViaString<T>(this int value) where T : struct
        {
            if (Enum.TryParse<T>(value.ToString(), out T result))
            {
                return result;
            }
            throw new ArgumentException($"{value} is not a valid ordinal of type {typeof(T)}.");
        }

        public static TEnum ToEnumExtensive<TEnum>(this object value)
        {
            Type type = typeof(TEnum);

            if (!type.IsEnum)
            {
                throw new ArgumentException($"{type} is not an enum.");
            }

            if (type.GetCustomAttributes(typeof(FlagsAttribute), true).Length > 0)
            {
                var values = Enum.GetValues(type);
                var underlyingType = Enum.GetUnderlyingType(type);
                switch (underlyingType.FullName)
                {
                    case "System.Byte":
                        {
                            var myVal = (byte)value;
                            foreach (byte val in values)
                            {
                                if ((myVal & val) > (byte)0)
                                {
                                    myVal ^= val;
                                }
                            }
                            if (myVal > (byte)0)
                            {
                                throw new ArgumentException($"{value} is not a valid ordinal of type {type}.");
                            }
                        }
                        break;
                    case "System.SByte":
                        {
                            var myVal = (sbyte)value;
                            foreach (sbyte val in values)
                            {
                                if ((myVal & val) > (sbyte)0)
                                {
                                    myVal ^= val;
                                }
                            }
                            if (myVal > (sbyte)0)
                            {
                                throw new ArgumentException($"{value} is not a valid ordinal of type {type}.");
                            }
                        }
                        break;
                    case "System.UInt16":
                        {
                            var myVal = (ushort)value;
                            foreach (ushort val in values)
                            {
                                if ((myVal & val) > (ushort)0)
                                {
                                    myVal ^= val;
                                }
                            }
                            if (myVal > (ushort)0)
                            {
                                throw new ArgumentException($"{value} is not a valid ordinal of type {type}.");
                            }
                        }
                        break;
                    case "System.Int16":
                        {
                            var myVal = (short)value;
                            foreach (short val in values)
                            {
                                if ((myVal & val) > (short)0)
                                {
                                    myVal ^= val;
                                }
                            }
                            if (myVal > (short)0)
                            {
                                throw new ArgumentException($"{value} is not a valid ordinal of type {type}.");
                            }
                        }
                        break;
                    case "System.UInt32":
                        {
                            var myVal = (uint)value;
                            foreach (uint val in values)
                            {
                                if ((myVal & val) > (uint)0)
                                {
                                    myVal ^= val;
                                }
                            }
                            if (myVal > (uint)0)
                            {
                                throw new ArgumentException($"{value} is not a valid ordinal of type {type}.");
                            }
                        }
                        break;
                    case "System.Int32":
                        {
                            var myVal = (int)value;
                            foreach (int val in values)
                            {
                                if ((myVal & val) > (int)0)
                                {
                                    myVal ^= val;
                                }
                            }
                            if (myVal > (int)0)
                            {
                                throw new ArgumentException($"{value} is not a valid ordinal of type {type}.");
                            }
                        }
                        break;
                    case "System.UInt64":
                        {
                            var myVal = (ulong)value;
                            foreach (ulong val in values)
                            {
                                if ((myVal & val) > (ulong)0)
                                {
                                    myVal ^= val;
                                }
                            }
                            if (myVal > (ulong)0)
                            {
                                throw new ArgumentException($"{value} is not a valid ordinal of type {type}.");
                            }
                        }
                        break;
                    case "System.Int64":
                        {
                            var myVal = (long)value;
                            foreach (long val in values)
                            {
                                if ((myVal & val) > (long)0)
                                {
                                    myVal ^= val;
                                }
                            }
                            if (myVal > (long)0)
                            {
                                throw new ArgumentException($"{value} is not a valid ordinal of type {type}.");
                            }
                        }
                        break;
                    default:
                        throw new ArgumentException($"{type} does not have a valid backing type ({underlyingType}).");
                        break;
                }
            }
            else
            {
                if (!type.IsEnumDefined(value))
                {
                    throw new ArgumentException($"{value} is not a valid ordinal of type {type}.");
                }
            }

            return (TEnum)Enum.ToObject(type, value);
        }
        public static TEnum ToEnumDynamic<TEnum>(dynamic value)
        {
            Type type = typeof(TEnum);

            if (!type.IsEnum)
            {
                throw new ArgumentException($"{type} is not an enum.");
            }

            if (type.GetCustomAttributes(typeof(FlagsAttribute), true).Length > 0)
            {
                var values = Enum.GetValues(type);

                void testEnum<T>(T myVal, Func<T, bool> aboveZero, Func<T, T, T> and, Func<T, T, T> xor)
                {
                    foreach (T val in values)
                    {
                        if (aboveZero(and(myVal, val)))
                        {
                            myVal = xor(myVal, val);
                        }
                    }
                    if (aboveZero(myVal))
                    {
                        throw new ArgumentException($"{value} is not a valid ordinal of type {type}.");
                    }
                }

                var underlyingType = Enum.GetUnderlyingType(type).FullName;
                switch (underlyingType)
                {
                    case "System.Byte":
                        testEnum((Byte)value, (v) => v > (Byte)0, (v1, v2) => (Byte)(v1 & v2), (v1, v2) => (Byte)(v1 ^ v2));
                        break;
                    case "System.SByte":
                        testEnum((SByte)value, (v) => v > (SByte)0, (v1, v2) => (SByte)(v1 & v2), (v1, v2) => (SByte)(v1 ^ v2));
                        break;
                    case "System.UInt16":
                        testEnum((UInt16)value, (v) => v > (UInt16)0, (v1, v2) => (UInt16)(v1 & v2), (v1, v2) => (UInt16)(v1 ^ v2));
                        break;
                    case "System.Int16":
                        testEnum((Int16)value, (v) => v > (Int16)0, (v1, v2) => (Int16)(v1 & v2), (v1, v2) => (Int16)(v1 ^ v2));
                        break;
                    case "System.UInt32":
                        testEnum((UInt32)value, (v) => v > (UInt32)0, (v1, v2) => (UInt32)(v1 & v2), (v1, v2) => (UInt32)(v1 ^ v2));
                        break;
                    case "System.Int32":
                        testEnum((Int32)value, (v) => v > (Int32)0, (v1, v2) => (Int32)(v1 & v2), (v1, v2) => (Int32)(v1 ^ v2));
                        break;
                    case "System.UInt64":
                        testEnum((UInt64)value, (v) => v > (UInt64)0, (v1, v2) => (UInt64)(v1 & v2), (v1, v2) => (UInt64)(v1 ^ v2));
                        break;
                    case "System.Int64":
                        testEnum((Int64)value, (v) => v > (Int64)0, (v1, v2) => (Int64)(v1 & v2), (v1, v2) => (Int64)(v1 ^ v2));
                        break;
                    default:
                        throw new ArgumentException($"{type} does not have a valid backing type ({underlyingType}).");
                        break;
                }
            }
            else
            {
                if (!type.IsEnumDefined(value))
                {
                    throw new ArgumentException($"{value} is not a valid ordinal of type {type}.");
                }
            }

            return (TEnum)Enum.ToObject(type, value);
        }
    }
\$\endgroup\$
2
  • \$\begingroup\$ Welcome to Code Review! You have presented an alternative solution, but haven't reviewed the code. Please edit to show what aspects of the question code prompted you to write this version, and in what ways it's an improvement over the original. It may be worth (re-)reading How to Answer. \$\endgroup\$ Commented Oct 7, 2021 at 6:56
  • \$\begingroup\$ I disagree. Yes, I provided an alternative solution but my code review was purely a comparison of performance of the original and other solutions including mine. While, it may not be traditional code review by picking apart specific aspects of the code, it does review the code. It doesn't seem appropriate to receive a negative vote because it doesn't meet your specific view of a code review. \$\endgroup\$
    – T Brown
    Commented Oct 7, 2021 at 15:08

Your Answer

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

Not the answer you're looking for? Browse other questions tagged or ask your own question.