C# 优化大量枚举比较

C# Optimizing mass enum comparison

有没有办法优化下面的代码:

enum ObjType
{
    A,
    B,
    C,
    D,
    E,
    F,
    G,
    H
}
...
if (instance.ObjType == ObjType.B
    || instance.ObjType == ObjType.D
    || instance.ObjType == ObjType.E
    || instance.ObjType == ObjType.F
    || instance.ObjType == ObjType.G
    || instance.ObjType == ObjType.H)
    doSmth();

以下解决方案不适合我:

if (instance.ObjType >= ObjType.B)
    doSmth();

因为不同的情况需要大量比较ObjType的不同组合。

一般来说,你的代码没有问题。这是惯用的 C#。

如果 "optimize" 是指 "get rid of all the redundancy",我建议如下:

var relevantTypes = new[] { ObjType.B, ObjType.D, ObjType.E, ... };

if (relevantTypes.Contains(instance.ObjType))
    doSmth();

局部变量只是一个示例,就我个人而言,我会将其设为 private static readonly 字段(因为您不能拥有 const 数组)。

如果您明智地选择名称,这也将使您的代码自文档化:

if (FooableTypes.Contains(instance.ObjType))
    doSmth();

if (TypesComparableToBar.Contains(instance.ObjType))
    doSmthElse();

如果您像这样手动分配值

enum ObjType
{
    A = 1,
    B = 2,
    C = 3,
    ...
    H = 8
}

您将能够使用数字比较。

同样,如果您使用枚举标志,您将能够使用位掩码:

[Flags]
enum ObjType
{
    A = 1,
    B = 2,
    C = 4,
    ...
    H = 256
}

if (((ObjType.A | ObjType.B | ObjType.C) & val) != 0) {
    ...
}

如果您必须经常进行这种比较并且希望使其更具可读性,那么一种可能的解决方案是扩展方法

public static IsBDEFGH(this ObjType oType)
{
    return oType == ObjType.B
        || oType == ObjType.D
        || oType == ObjType.E
        || oType == ObjType.F
        || oType == ObjType.G
        || oType == ObjType.H;
}

然后像这样使用它

if(instance.ObjType.IsBDEFGH())
{
}

选择一个好名字,可以清楚地表明比较的值是什么。

您可以将枚举定义为标记枚举

[Flags]
enum ObjType
{
    None = 0,
    A = 1 << 0,
    B = 1 << 1,
    C = 1 << 2,
    D = 1 << 3,
    E = 1 << 4,
    F = 1 << 5,
    G = 1 << 6,
    H = 1 << 7,
    MyCombination1 = A | B | D,
    MyCombination2 = C | F | G | H
}

这样您最多可以定义 32 个值(加上 None = 0 和任意数量的其他值组合)或最多 64 个值

[Flags]
enum ObjType : long
{
    None = 0,
    A = 1L << 0,
    B = 1L << 1,
    ...
}

现在你可以比较

if (instance.ObjType & ObjType.MyCombination1 != ObjType.None) {
   ...
}

如果更适合您的需要,您也可以在枚举本身之外定义常量

private const ObjType AdHocCombination = ObjType.A | ObjType.C | ObjType.H;

定义标志时,值必须是 2 的幂(None 除外)。这可以通过使用左移运算符 <<.

轻松实现

根据您的需要,您可以使用 [Flags] 如下:

[Flags]
enum ObjType 
{
    SomethingSpecial = 1 << 0,
    SomethingSpecialElse = 1 << 1,

    A = (1 << 16),
    B = (1 << 17) | ObjType.SomethingSpecial,
    C = (1 << 18) | ObjType.SomethingSpecialElse,
    D = (1 << 19) | ObjType.SomethingSpecial | ObjType.SomethingSpecialElse,
}

然后您可以使用 HasFlag 方法:

    ObjType.A.HasFlag(ObjType.SomethingSpecial);        // false
    ObjType.A.HasFlag(ObjType.SomethingSpecialElse);    // false
    ObjType.B.HasFlag(ObjType.SomethingSpecial);        // true
    ObjType.B.HasFlag(ObjType.SomethingSpecialElse);    // false
    ObjType.C.HasFlag(ObjType.SomethingSpecial);        // false
    ObjType.C.HasFlag(ObjType.SomethingSpecialElse);    // true
    ObjType.D.HasFlag(ObjType.SomethingSpecial);        // true
    ObjType.D.HasFlag(ObjType.SomethingSpecialElse);    // true