Cast Int to Generic Enum in C#
Solution 1
The simplest way I have found is to force the compiler's hand by adding a cast to object
.
return (T)(object)i.Value;
Solution 2
You should be able to use Enum.Parse
for this:
return (T)Enum.Parse(typeof(T), i.Value.ToString(), true);
This article talks about parsing generic enums for extenstion methods:
Solution 3
Here's a very fast solution that abuses the fact that the runtime creates multiple instances of static generic classes. Unleash your inner optimization demons!
This really shines when you're reading Enums from a stream in a generic fashion. Combine with an outer class that also caches the enum's underlying type and a BitConverter to unleash the awesome.
void Main()
{
Console.WriteLine("Cast (reference): {0}", (TestEnum)5);
Console.WriteLine("EnumConverter: {0}", EnumConverter<TestEnum>.Convert(5));
Console.WriteLine("Enum.ToObject: {0}", Enum.ToObject(typeof(TestEnum), 5));
int iterations = 1000 * 1000 * 100;
Measure(iterations, "Cast (reference)", () => { var t = (TestEnum)5; });
Measure(iterations, "EnumConverter", () => EnumConverter<TestEnum>.Convert(5));
Measure(iterations, "Enum.ToObject", () => Enum.ToObject(typeof(TestEnum), 5));
}
static class EnumConverter<TEnum> where TEnum : struct, IConvertible
{
public static readonly Func<long, TEnum> Convert = GenerateConverter();
static Func<long, TEnum> GenerateConverter()
{
var parameter = Expression.Parameter(typeof(long));
var dynamicMethod = Expression.Lambda<Func<long, TEnum>>(
Expression.Convert(parameter, typeof(TEnum)),
parameter);
return dynamicMethod.Compile();
}
}
enum TestEnum
{
Value = 5
}
static void Measure(int repetitions, string what, Action action)
{
action();
var total = Stopwatch.StartNew();
for (int i = 0; i < repetitions; i++)
{
action();
}
Console.WriteLine("{0}: {1}", what, total.Elapsed);
}
Results on Core i7-3740QM with optimizations enabled:
Cast (reference): Value
EnumConverter: Value
Enum.ToObject: Value
Cast (reference): 00:00:00.3175615
EnumConverter: 00:00:00.4335949
Enum.ToObject: 00:00:14.3396366
Solution 4
In .NET core it is now possible to use System.Runtime.CompilerServices.Unsafe code like this:
return Unsafe.As<int, TEnum>(ref int32);
Solution 5
Alternatively, if you can get a enum not as a generic type, but as Type, then simply use
Enum.ToObject
https://msdn.microsoft.com/en-us/library/system.enum.toobject(v=vs.110).aspx
Related videos on Youtube
cariseldon
Sr. Software Developer @ Nudge.ai Mostly work with C#, Java, JavaScript, Bash
Updated on July 27, 2021Comments
-
cariseldon almost 3 years
Similar to Cast int to enum in C# but my enum is a Generic Type parameter. What is the best way to handle this?
Example:
private T ConvertEnum<T>(int i) where T : struct, IConvertible { return (T)i; }
Generates compiler error
Cannot convert type 'int' to 'T'
Full code is as follows, where value can contain the int, or null.
private int? TryParseInt(string value) { var i = 0; if (!int.TryParse(value, out i)) { return null; } return i; } private T? TryParseEnum<T>(string value) where T : struct, IConvertible { var i = TryParseInt(value); if (!i.HasValue) { return null; } return (T)i.Value; }
-
Sunny about 12 yearsstackoverflow.com/questions/2745320/… - might help?
-
Tony Hopkinson about 12 yearsLast answer on stackoverflow.com/questions/1331739/…, is closer to what you want. It's still not clever though. I tend to use reflection for this, you can make the code a lot stronger. Struct isn't retrictive enough to make messing about with generics worthwhile in my opinion.
-
nawfal almost 11 yearsSomething that doesn't box: c-sharp-non-boxing-conversion-of-generic-enum-to-int
-
-
James Johnson about 12 years@Guvante: I think I converted the value to a string in my example. Do you foresee this causing an issue?
-
nawfal almost 11 yearsIf you don't like boxing: c-sharp-non-boxing-conversion-of-generic-enum-to-int
-
MatteoSp about 9 yearsWe are casting enum to int, not the contrary as in the So question you link. Also, that question has no solution.
-
Drew Noakes about 9 yearsThis is really nice, thanks. You might like to use
Expression.ConvertChecked
instead though, so that numeric overflow of the enum type's range results in anOverflowException
. -
Krythic almost 7 yearsYou could also just allocate a static array with the enum values, and then just pass in the index to retrieve the correct enum. This saves having to do any kind of casting. Example(Only line 11,14, and 34 are relevant to this concept): pastebin.com/iPEzttM4
-
Herman almost 5 yearsYour mileage might vary, I ran the code on try.dot.net (blazor) and there the EnumConverter<T> is much slower than the alternatives. Casting to object first was about 6 times slower than a direct cast, but still far better than the other options.
-
Dunno about 3 yearsI feel kind of evil doing this, but hey, it works
-
Oscar Abraham almost 3 yearsThis will throw an exception if the enum's underlying type is not int (i.e. byte or long enums, even uint).
-
Xela.Trawets almost 3 yearsAnd of course the same thing can be done without using linq, replacing the .Zip, .ToDictionary lines with Dictionary<int, TEnum> c = new Dictionary<int, TEnum>(array.Length); for (int j = 0; j < array.Length; j++) c.Add(intValues[j], enumValues[j]);
-
Xela.Trawets almost 3 yearsAlso same Array cast can be used to set a generic enum to an arbitrary integer value; TEnum enumValue = ((TEnum[])(Array)(new int[] { -1 }))[0];
-
trinalbadger587 almost 3 yearsYou can see this answer on .NET fiddle: dotnetfiddle.net/Nrc2oL
-
Mike Christiansen about 2 yearsYou can add some constraints on there. Makes the
if (info.IsEnum)
check unnecessary.public static T ToEnum<T>(this int param) where T : struct, Enum