C#
enums
conversion
performance
generics

C non-boxing conversion of generic enum to int?

Master System Design with Codemia

Enhance your system design skills with over 120 practice problems, detailed solutions, and hands-on exercises.

Introduction

In C#, converting an enum to an integer is easy when the enum type is known at compile time. The problem gets more subtle in generic code, because not every enum is backed by int, and many obvious conversion APIs box the value. So the real answer is: a fully general, safe, non-boxing conversion to int is not always possible, but there are efficient patterns when you know the enum's underlying type.

Why Boxing Shows Up

Enums are value types, but many convenience APIs accept object, Enum, or interfaces implemented through boxing. For example, these patterns can allocate or box:

csharp
int boxed1 = (int)(object)DayOfWeek.Monday;
int boxed2 = Convert.ToInt32(DayOfWeek.Monday);

In non-generic code, a direct cast such as (int)myEnum is fine when the underlying type really is int. In generic code, the compiler cannot assume that for TEnum.

Constrain the Generic Type Properly

Modern C# lets you constrain a generic parameter to enum types:

csharp
1public static string Describe<TEnum>(TEnum value) where TEnum : struct, Enum
2{
3    return $"{typeof(TEnum).Name} = {value}";
4}

This constraint prevents unrelated value types from being passed in, but it still does not mean every TEnum can safely be reinterpreted as int. Some enums are backed by byte, short, long, and other integral types.

Safe Conversion When the Underlying Type Is Known to Be int

If you control the API and know that every enum passed in is backed by int, you can use Unsafe.As to reinterpret the bits without boxing.

csharp
1using System;
2using System.Runtime.CompilerServices;
3
4public static class EnumHelpers
5{
6    public static int ToInt32Fast<TEnum>(TEnum value) where TEnum : struct, Enum
7    {
8        if (Enum.GetUnderlyingType(typeof(TEnum)) != typeof(int))
9        {
10            throw new InvalidOperationException("TEnum must use int as its underlying type.");
11        }
12
13        return Unsafe.As<TEnum, int>(ref value);
14    }
15}
16
17enum Status
18{
19    Ready = 1,
20    Running = 2
21}
22
23Console.WriteLine(EnumHelpers.ToInt32Fast(Status.Running));

This avoids boxing during the actual value read. The important guard is the Enum.GetUnderlyingType check. Without it, reinterpreting a non-int enum as int is incorrect.

Why There Is No Universal int Answer

Consider these enum declarations:

csharp
1enum SmallCode : byte
2{
3    Ok = 1,
4    Error = 2
5}
6
7enum LargeCode : long
8{
9    First = 10,
10    Second = 20
11}

Neither one is naturally "an int enum". Converting them generically to int may require widening or truncation rules, and those rules are not universal. That is why the compiler cannot simply allow a generic cast from TEnum to int.

A More General Alternative

If the real goal is "get a numeric value from any enum", using long or ulong is often a better abstraction. You can then decide how to handle signedness and range explicitly.

csharp
1using System;
2
3public static class EnumHelpers
4{
5    public static long ToInt64Boxed<TEnum>(TEnum value) where TEnum : struct, Enum
6    {
7        return Convert.ToInt64(value);
8    }
9}

This version is simple and correct for many cases, but it may box. That is often acceptable unless profiling proves the conversion is on a hot path.

When Performance Actually Matters

If enum conversion is happening inside a tight loop, serializer, parser, or high-frequency generic utility, micro-allocations can matter. In those cases:

  • Prefer specialized overloads when possible
  • Use where TEnum : struct, Enum
  • Use Unsafe.As only when the underlying type is guaranteed
  • Benchmark before adding complexity

For many business applications, the boxing cost is so small compared with I/O, database work, or UI updates that the simpler code is the better tradeoff.

Common Pitfalls

One common mistake is assuming every enum is backed by int. int is the default, but C# allows several other integral backing types.

Another issue is using Unsafe.As<TEnum, int> without checking the underlying type. That can reinterpret the wrong number of bytes and produce invalid results.

Developers also sometimes over-optimize too early. A non-boxing helper is only worth the extra complexity if profiling shows the conversion is frequent enough to matter.

Finally, do not confuse enum constraints with numeric constraints. where TEnum : struct, Enum guarantees that the type is an enum, not that it is directly castable to int.

Summary

  • A generic enum cannot always be converted to int safely without extra assumptions.
  • 'where TEnum : struct, Enum is the right starting constraint for enum-based generic code.'
  • Use Unsafe.As<TEnum, int> only when the enum is guaranteed to be int-backed.
  • If you need a fully general solution, correctness may matter more than eliminating boxing.
  • Measure first before introducing unsafe or specialized conversion code.

Course illustration
Course illustration

All Rights Reserved.