C#:检查一组枚举值的最佳方法?

发布于 2024-12-05 23:06:40 字数 314 浏览 4 评论 0原文

假设你有 enum MyEnum {A = 0, B = 1, C = 2, D = 4, E = 8, F = 16};

在某些时候,您有一个函数可以检查 MyEnum 的实例并如果是 C、D 或 F,则返回 true

bool IsCDF(MyEnum enumValue) 
{
  return //something slick
}

我记得有一些非常巧妙的方法来进行位移并执行此操作,该方法比一堆三元 if 语句读起来更好,但对于我的生活,我不记得了什么 这是。

有人知道吗?

suppose you have
enum MyEnum {A = 0, B = 1, C = 2, D = 4, E = 8, F = 16};

At some point you have a function that will check an instance of MyEnum and return true if it is C,D, or F

bool IsCDF(MyEnum enumValue) 
{
  return //something slick
}

I remember that there was some really slick way to do bit shifting and preform this operation that read way better than a bunch of ternary if statements but for the life of me I can't remember what it is.

Anyone know?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(8

錯遇了你 2024-12-12 23:06:41
bool IsCDF(MyEnum enumValue) 
{
  return new[]{MyEnum.C, MyEnum.D, MyEnum.F}.Contains(enumValue);
}
bool IsCDF(MyEnum enumValue) 
{
  return new[]{MyEnum.C, MyEnum.D, MyEnum.F}.Contains(enumValue);
}
〃温暖了心ぐ 2024-12-12 23:06:41

如果将其设为[Flags] 枚举,则可以为每个枚举值分配不同的位值(1、2、4、8、16...)。然后,您可以使用按位运算来确定某个值是否是一组可能值中的一个。

因此,要查看它是 C、D 还是 F:

bool IsCDF(MyEnum enumValue)
{
    return ((enumValue & (MyEnum.C | MyEnum.D | MyEnum.F)) != 0);
}

或使用 HasFlag() (效率较低,但可读性更强):

bool IsCDF(MyEnum enumValue)
{
    return enumValue.HasFlag(MyEnum.C | MyEnum.D | MyEnum.F);
}

请注意,这对于 0 值不起作用(在您的示例中, 'A'),并且您必须小心所有枚举值都解析为唯一的位值(即 2 的非零幂)。

这种方法的优点是:

  • 它通常需要单个 CPU 指令/周期来执行,而执行三个单独的“if”检查将需要 3 个或更多指令(取决于您的目标平台)。
  • 您可以将要测试的值集作为枚举值(单个整数)传递,而无需使用枚举值列表。
  • 您可以使用按位运算做许多其他有用的事情,这对于普通的数值/比较方法来说会很笨重且缓慢。

方便提示:
定义 [Flags] 枚举时,使用左移 (<<) 使位值更清晰(并且更难出错),尤其是对于高阶位:

[Flags]
enum MyEnum
{
    A = 1 << 0,     // Equivalent to 1
    B = 1 << 1,     // Equivalent to 2
    C = 1 << 2,     // Equivalent to 4
    D = 1 << 3,     // Equivalent to 8
    …
    Big = 1 << 26,  // Equivalent to 67108864
}

If you make it a [Flags] enum, you can assign a different bit value (1, 2, 4, 8, 16...) to each enumerated value. Then you can use a bitwise operation to determine if a value is one of a set of possible values.

So, to see if it is C, D, or F:

bool IsCDF(MyEnum enumValue)
{
    return ((enumValue & (MyEnum.C | MyEnum.D | MyEnum.F)) != 0);
}

or using HasFlag() (less efficient but more readable):

bool IsCDF(MyEnum enumValue)
{
    return enumValue.HasFlag(MyEnum.C | MyEnum.D | MyEnum.F);
}

Note that this will not work for a value of 0 (in your example, 'A'), and you must be careful that all enum values resolve to unique bit values (i.e. non-zero powers of two).

The advantages of this approach are:

  • it will typically take a single CPU instruction/cycle to execute, whereas doing three separate "if" checks will take 3 or more instructions (depending on your target platform).
  • You can pass the set of values that you want to test with as an enum value (a single integer) instead of needing to use lists of enum values.
  • You can do lots of other useful things with bitwise operations, which would be clunky and slow with ordinary numerical/comparative approaches.

Handy hint:
When defining [Flags] enums, use left-shift (<<) to make the bit values clearer (and much harder to get wrong) especially for higher-order bits:

[Flags]
enum MyEnum
{
    A = 1 << 0,     // Equivalent to 1
    B = 1 << 1,     // Equivalent to 2
    C = 1 << 2,     // Equivalent to 4
    D = 1 << 3,     // Equivalent to 8
    …
    Big = 1 << 26,  // Equivalent to 67108864
}
酒解孤独 2024-12-12 23:06:41

我可能会使用 Unconstrained Melody 作为保持事情整洁的方式:

if (value.HasAny(MyEnum.C | MyEnum.D | MyEnum.E))
{
    ...
}

我可能会提取命名常量中的“C、D 或 E”位 - 可能在枚举本身中,如果它有意义的话:

I'd possibly use Unconstrained Melody as a way of keeping things tidy:

if (value.HasAny(MyEnum.C | MyEnum.D | MyEnum.E))
{
    ...
}

I'd probably extract the "C, D or E" bit into a named constant - possibly in the enum itself, if it had meaning:

゛清羽墨安 2024-12-12 23:06:41

这是我创建的一个扩展,它允许您查看给定的枚举值是否位于枚举值的可能选择的变量列表中。

using System.Linq;
public static class ExtensionMethods
{
    public static bool IsAny<T>(this T value, params T[] choices)
        where T : Enum
    {
        return choices.Contains(value);
    }
}

用法

bool IsCDF(MyEnum enumValue) 
{
    return enumValue.IsAny(MyEnum.C, MyEnum.D, MyEnum.F);
}

Here is an extension I created that allows you to see if your given Enum value is in a variable list of possible choices of Enum values.

using System.Linq;
public static class ExtensionMethods
{
    public static bool IsAny<T>(this T value, params T[] choices)
        where T : Enum
    {
        return choices.Contains(value);
    }
}

Usage

bool IsCDF(MyEnum enumValue) 
{
    return enumValue.IsAny(MyEnum.C, MyEnum.D, MyEnum.F);
}
青丝拂面 2024-12-12 23:06:41

您可能正在考虑 FlagsAttribute。请查看此处此处查看一些示例。

您可以使用 Enum.HasFlag 方法

May be you are thinking of FlagsAttribute. Look at here and here for some examples.

You could use Enum.HasFlag Method

时光是把杀猪刀 2024-12-12 23:06:41

也许这个扩展类对你有用:

public static class Flags
{
    /// <summary>
    /// Checks if the type has any flag of value.
    /// </summary>
    /// <typeparam name="T"></typeparam>
    /// <param name="type"></param>
    /// <param name="value"></param>
    /// <returns></returns>
    public static bool HasAny<T>(this System.Enum type, T value)
    {
        try
        {
            return (((int) (object) type & (int) (object) value) != 0);
        }
        catch
        {
            return false;
        }
    }

    /// <summary>
    /// Checks if the value contains the provided type.
    /// </summary>
    /// <typeparam name="T"></typeparam>
    /// <param name="type"></param>
    /// <param name="value"></param>
    /// <returns></returns>
    public static bool Has<T>(this System.Enum type, T value)
    {
        try
        {
            return (((int)(object)type & (int)(object)value) == (int)(object)value);
        }
        catch
        {
            return false;
        }
    }

    /// <summary>
    /// Checks if the value is only the provided type.
    /// </summary>
    /// <typeparam name="T"></typeparam>
    /// <param name="type"></param>
    /// <param name="value"></param>
    /// <returns></returns>
    public static bool Is<T>(this System.Enum type, T value)
    {
        try
        {
            return (int)(object)type == (int)(object)value;
        }
        catch
        {
            return false;
        }
    }

    /// <summary>
    /// Appends a value.
    /// </summary>
    /// <typeparam name="T"></typeparam>
    /// <param name="type"></param>
    /// <param name="value"></param>
    /// <returns></returns>
    public static T Add<T>(this System.Enum type, T value)
    {
        try
        {
            return (T)(object)(((int)(object)type | (int)(object)value));
        }
        catch (Exception ex)
        {
            throw new ArgumentException(
                string.Format(
                    "Could not append value from enumerated type '{0}'.",
                    typeof(T).Name
                    ), ex);
        }
    }

    /// <summary>
    /// Appends a value.
    /// </summary>
    /// <typeparam name="T"></typeparam>
    /// <param name="type"></param>
    /// <param name="value"></param>
    /// <returns></returns>
    public static void AddTo<T>(this System.Enum type, ref T value)
    {
        try
        {
            value = (T)(object)(((int)(object)type | (int)(object)value));
        }
        catch (Exception ex)
        {
            throw new ArgumentException(
                string.Format(
                    "Could not append value from enumerated type '{0}'.",
                    typeof(T).Name
                    ), ex);
        }
    }

    /// <summary>
    /// Removes the value.
    /// </summary>
    /// <typeparam name="T"></typeparam>
    /// <param name="type"></param>
    /// <param name="value"></param>
    /// <returns></returns>
    public static T Remove<T>(this System.Enum type, T value)
    {
        try
        {
            return (T)(object)(((int)(object)type & ~(int)(object)value));
        }
        catch (Exception ex)
        {
            throw new ArgumentException(
                string.Format(
                    "Could not remove value from enumerated type '{0}'.",
                    typeof(T).Name
                    ), ex);
        }
    }

    /// <summary>
    /// Removes the value.
    /// </summary>
    /// <typeparam name="T"></typeparam>
    /// <param name="type"></param>
    /// <param name="value"></param>
    /// <returns></returns>
    public static void RemoveFrom<T>(this System.Enum type, ref T value)
    {
        try
        {
            value = (T)(object)(((int)(object)type & ~(int)(object)value));
        }
        catch (Exception ex)
        {
            throw new ArgumentException(
                string.Format(
                    "Could not remove value from enumerated type '{0}'.",
                    typeof(T).Name
                    ), ex);
        }
    }
}

Maybe this extension class is usefull for you:

public static class Flags
{
    /// <summary>
    /// Checks if the type has any flag of value.
    /// </summary>
    /// <typeparam name="T"></typeparam>
    /// <param name="type"></param>
    /// <param name="value"></param>
    /// <returns></returns>
    public static bool HasAny<T>(this System.Enum type, T value)
    {
        try
        {
            return (((int) (object) type & (int) (object) value) != 0);
        }
        catch
        {
            return false;
        }
    }

    /// <summary>
    /// Checks if the value contains the provided type.
    /// </summary>
    /// <typeparam name="T"></typeparam>
    /// <param name="type"></param>
    /// <param name="value"></param>
    /// <returns></returns>
    public static bool Has<T>(this System.Enum type, T value)
    {
        try
        {
            return (((int)(object)type & (int)(object)value) == (int)(object)value);
        }
        catch
        {
            return false;
        }
    }

    /// <summary>
    /// Checks if the value is only the provided type.
    /// </summary>
    /// <typeparam name="T"></typeparam>
    /// <param name="type"></param>
    /// <param name="value"></param>
    /// <returns></returns>
    public static bool Is<T>(this System.Enum type, T value)
    {
        try
        {
            return (int)(object)type == (int)(object)value;
        }
        catch
        {
            return false;
        }
    }

    /// <summary>
    /// Appends a value.
    /// </summary>
    /// <typeparam name="T"></typeparam>
    /// <param name="type"></param>
    /// <param name="value"></param>
    /// <returns></returns>
    public static T Add<T>(this System.Enum type, T value)
    {
        try
        {
            return (T)(object)(((int)(object)type | (int)(object)value));
        }
        catch (Exception ex)
        {
            throw new ArgumentException(
                string.Format(
                    "Could not append value from enumerated type '{0}'.",
                    typeof(T).Name
                    ), ex);
        }
    }

    /// <summary>
    /// Appends a value.
    /// </summary>
    /// <typeparam name="T"></typeparam>
    /// <param name="type"></param>
    /// <param name="value"></param>
    /// <returns></returns>
    public static void AddTo<T>(this System.Enum type, ref T value)
    {
        try
        {
            value = (T)(object)(((int)(object)type | (int)(object)value));
        }
        catch (Exception ex)
        {
            throw new ArgumentException(
                string.Format(
                    "Could not append value from enumerated type '{0}'.",
                    typeof(T).Name
                    ), ex);
        }
    }

    /// <summary>
    /// Removes the value.
    /// </summary>
    /// <typeparam name="T"></typeparam>
    /// <param name="type"></param>
    /// <param name="value"></param>
    /// <returns></returns>
    public static T Remove<T>(this System.Enum type, T value)
    {
        try
        {
            return (T)(object)(((int)(object)type & ~(int)(object)value));
        }
        catch (Exception ex)
        {
            throw new ArgumentException(
                string.Format(
                    "Could not remove value from enumerated type '{0}'.",
                    typeof(T).Name
                    ), ex);
        }
    }

    /// <summary>
    /// Removes the value.
    /// </summary>
    /// <typeparam name="T"></typeparam>
    /// <param name="type"></param>
    /// <param name="value"></param>
    /// <returns></returns>
    public static void RemoveFrom<T>(this System.Enum type, ref T value)
    {
        try
        {
            value = (T)(object)(((int)(object)type & ~(int)(object)value));
        }
        catch (Exception ex)
        {
            throw new ArgumentException(
                string.Format(
                    "Could not remove value from enumerated type '{0}'.",
                    typeof(T).Name
                    ), ex);
        }
    }
}
荒岛晴空 2024-12-12 23:06:41

在 c# 8 中你可以这样做:

public class MyClass
{
    public static bool IsCDF(MyEnum enumValue) 
    {
        enumValue is MyEnum.C or MyEnum.D or MyEnum.F;
        // enumValue is not (MyEnum.C or MyEnum.D) // for nots
    }
}

使用扩展方法方式:

public static class EnumExtensions
{
    public static bool ContainsAnyFlag<T>(this T enumValue, params T[] flags) where T : Enum
    {
        return flags.Any(flag => enumValue.HasFlag(flag));
    }
}

var enumValue = MyEnum.A;
Console.WriteLine(enumValue.ContainsAnyFlag(MyEnum.C, MyEnum.B, MyEnum.D)); // Output: False
Console.WriteLine(enumValue.ContainsAnyFlag(MyEnum.A, MyEnum.B)); // Output: True

否则你可以这样做:

public static bool IsCDF(MyEnum enumValue)
{
    MyEnum flags = MyEnum.C | MyEnum.D | MyEnum.F;
    return (enumValue & flags) != 0;
}

in c# 8 you can do:

public class MyClass
{
    public static bool IsCDF(MyEnum enumValue) 
    {
        enumValue is MyEnum.C or MyEnum.D or MyEnum.F;
        // enumValue is not (MyEnum.C or MyEnum.D) // for nots
    }
}

Using an extension method way:

public static class EnumExtensions
{
    public static bool ContainsAnyFlag<T>(this T enumValue, params T[] flags) where T : Enum
    {
        return flags.Any(flag => enumValue.HasFlag(flag));
    }
}

var enumValue = MyEnum.A;
Console.WriteLine(enumValue.ContainsAnyFlag(MyEnum.C, MyEnum.B, MyEnum.D)); // Output: False
Console.WriteLine(enumValue.ContainsAnyFlag(MyEnum.A, MyEnum.B)); // Output: True

otherwise you could do:

public static bool IsCDF(MyEnum enumValue)
{
    MyEnum flags = MyEnum.C | MyEnum.D | MyEnum.F;
    return (enumValue & flags) != 0;
}
请你别敷衍 2024-12-12 23:06:41
return (enumValue & MyEnum.C == MyEnum.C) 
       || (enumValue & MyEnum.D == MyEnum.D) 
       || (enumValue & MyEnum.F == MyEnum.F);
return (enumValue & MyEnum.C == MyEnum.C) 
       || (enumValue & MyEnum.D == MyEnum.D) 
       || (enumValue & MyEnum.F == MyEnum.F);
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文