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

Kno*_*eus 4 .net c# reflection enums .net-standard

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

public static void SetFlag<TEnum>(ref TEnum value, TEnum flag)
    where TEnum : Enum
Run Code Online (Sandbox Code Playgroud)

我花了几个小时试图实现这一目标:

  • |对于像 s 这样的基本类型来说,通过反射获取运算符似乎是不可能的enum
  • 使用dynamic需要引用额外的包 ( Microsoft.CSharp.RuntimeBinder),但我希望我的库保持纯粹的 .NET 标准符合。

我最新的想法是手动比较 TEnum每个有效的枚举类型{byte , sbyte, short, ushort, int, uint, long, ulong}。但这感觉真的很奇怪而且肮脏:

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)}");
Run Code Online (Sandbox Code Playgroud)

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

编辑:不是这个问题的重复;我正在使用 C# 7.3 和通用Enum约束。

can*_*on7 5

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

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);
    }
}
Run Code Online (Sandbox Code Playgroud)

你仍然有一些重复,但至少它被限制在long/ulong. 如果您可以假设您的标志枚举成员不会有负值,您可以使用:

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);
}
Run Code Online (Sandbox Code Playgroud)

  • 几乎肯定会更快。抛出异常的成本非常高(相对而言),并且您的方法在找到正确的类型之前可能会抛出相当多的异常(特别是当您从“byte”开始时)。至少我会检查“Enum.GetUnderlyingType()”,而不是冒着出现异常的风险。除此之外,我通常遵循代码重复越少越好的规则。不要忘记你的方法也有很多限制。 (2认同)