【问题标题】:How set an enum flag for a generic enum type in .NET Standard?如何在 .NET Standard 中为通用枚举类型设置枚举标志?
【发布时间】:2019-04-04 13:09:13
【问题描述】:

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

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

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

  • 对于像enums 这样的原始类型,通过反射 获取| 运算符似乎是不可能的。
  • 使用 dynamic 需要引用一个额外的包 (Microsoft.CSharp.RuntimeBinder),但我希望我的库保持完全符合 .NET Standard。

我的最新想法是手动比较TEnum的每个有效枚举类型{bytesbyteshortushortintuintlongulong}。但这感觉真的很奇怪和肮脏:

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

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

编辑:不是this question的重复;我正在使用 C# 7.3 和通用 Enum 约束。

【问题讨论】:

  • @Corak 我不这么认为,因为我使用的是System.Enum 约束。
  • 是的,我刚刚意识到 - 我删除了我的评论!
  • @KnorxThieus - 是的,对不起。我完全预料到这是可能的。
  • 我建议的副本具有功能通用的方法,可以对任何类型和基础大小的枚举执行各种按位运算,而无需装箱。请参阅琼斯医生的答案(优化了我的解决方案)。

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


【解决方案1】:

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

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。如果您可以假设您的标志枚举成员不会有负值,您可以使用:

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

【讨论】:

  • 感谢您的提交。为什么你更喜欢这个解决方案而不是我上面的建议?哪种方法应该更快?
  • 它几乎肯定会更快。抛出异常非常昂贵(相对而言),并且您的方法可能会在找到正确的类型之前抛出相当多的异常(特别是当您以 byte 开头时)。至少我会检查Enum.GetUnderlyingType(),而不是冒着获得异常的风险。除此之外,我通常遵循代码重复越少越好的规则。不要忘记你的方法也有很多问题。
  • 谢谢。有趣的是,即使是 Microsoft 在其 Enum 实现中也没有区分 ulong 和 Co. [1] referencesource.microsoft.com/#mscorlib/system/enum.cs,158
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多