Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How set an enum flag for a generic enum type in .NET Standard?

I want to implement the following method using .NET Standard:

public static void SetFlag<TEnum>(ref TEnum value, TEnum flag)
    where TEnum : Enum

I spend hours in trying to achieve this:

  • Getting the | operator via reflection appears to be impossible for primitive types as enums are.
  • Using dynamic requires referencing an extra package (Microsoft.CSharp.RuntimeBinder), but I would like my library to stay pure .NET Standard conform.

My latest idea was to manually compare TEnum to each valid enum type of {byte, sbyte, short, ushort, int, uint, long, ulong}. But this feels really weird and dirty:

try
{
    var v = (byte)(object)value | (byte)(object)flag;
    value = (TEnum)(object)v;
    return;
}
catch (InvalidCastException) { }

try
{
    var v = (int)(object)value | (int)(object)flag;
    value = (TEnum)(object)v;
    return;
}
catch (InvalidCastException) { }

// ...

throw new NotSupportException($"Unknown enum type {typeof(TEnum)}");

So is this really the only option .NET (Standard) provides here or what I am missing? Looking forward to your hints!

Edit: Not a duplicate of this question; I am using C# 7.3 and the generic Enum constraint.

like image 956
KnorxThieus Avatar asked Oct 27 '25 17:10

KnorxThieus


1 Answers

It's not the cheapest (everything gets boxed, there's some reflection, etc), but you could always do something like this:

private static void SetFlag<T>(ref T value, T flag) where T : Enum
{
    // 'long' can hold all possible values, except those which 'ulong' can hold.
    if (Enum.GetUnderlyingType(typeof(T)) == typeof(ulong))
    {
        ulong numericValue = Convert.ToUInt64(value);
        numericValue |= Convert.ToUInt64(flag);
        value = (T)Enum.ToObject(typeof(T), numericValue);
    }
    else
    {
        long numericValue = Convert.ToInt64(value);
        numericValue |= Convert.ToInt64(flag);
        value = (T)Enum.ToObject(typeof(T), numericValue);
    }
}

You've still got some repetition, but at least it's restricted to long/ulong. If you can assume that your flags enum members won't have negative values, you can just use:

private static void SetFlag<T>(ref T value, T flag) where T : Enum
{
    ulong numericValue = Convert.ToUInt64(value);
    numericValue |= Convert.ToUInt64(flag);
    value = (T)Enum.ToObject(typeof(T), numericValue);
}
like image 123
canton7 Avatar answered Oct 29 '25 07:10

canton7



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!