如何在.NET Standard中为通用枚举类型设置枚举标志?

时间:2019-04-04 13:09:14

标签: c# .net reflection enums .net-standard

我想使用.NET Standard实现以下方法:

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

我花了很多时间来实现这一目标:

  • 对于像|这样的原始类型,通过 reflection 获取enum运算符似乎是不可能的。
  • 使用 dynamic 需要引用一个额外的程序包(Microsoft.CSharp.RuntimeBinder),但我希望我的库保持纯净的.NET Standard一致性。

我的最新想法是手动比较 TEnum { bytesbyte,{{ 1}},shortushortintuintlong } 。但这感觉真的很奇怪又肮脏:

ulong

那么,这真的是.NET(标准版)在这里提供的唯一选项吗?还是我所缺少的?期待您的提示!

修改:不是this question的重复项;我正在使用C#7.3和通用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)}"); 约束。

1 个答案:

答案 0 :(得分:3)

它不是最便宜的(所有东西都装箱了,有一些反射等),但是您总是可以做这样的事情:

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);
    }
}

您仍然有一些重复,但至少限于long/ulong。如果您可以假设自己的flags枚举成员没有负值,则可以使用:

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);
}