简体   繁体   English

确定Enum-flag组合中包含的标志数量的最佳做法?

[英]Best practice to determine the amount of flags contained in a Enum-flag combination?

In some scenarios, when I pass a Enum to a method, I need to handle whether it is a single Enum value, or otherwise it is a flag combination, for that purpose I wrote this simple extension: 在某些情况下,当我将Enum传递给方法时,我需要处理它是否是单个Enum值,否则它是一个标志组合,为此我编写了这个简单的扩展:

Vb.Net: Vb.Net:

<Extension>
Public Function FlagCount(ByVal sender As System.[Enum]) As Integer
    Return sender.ToString().Split(","c).Count()
End Function

C# (online translation): C#(在线翻译):

[Extension()]
public int FlagCount(this System.Enum sender) {
    return sender.ToString().Split(',').Count();
}

Example Usage: 用法示例:

Vb.Net: Vb.Net:

Dim flags As FileAttributes = (FileAttributes.Archive Or FileAttributes.Compressed)
Dim count As Integer = flags.FlagCount()
MessageBox.Show(flagCount.ToString())

C# (online translation): C#(在线翻译):

FileAttributes flags = (FileAttributes.Archive | FileAttributes.Compressed);
int count = flags.FlagCount();
MessageBox.Show(flagCount.ToString());

I just would like to ask If exists a more direct and efficient way that what I'm currently doing to avoid represent the flag combination as a String then split it. 我只是想问一下,如果存在一种更直接,更有效的方式,我现在正在做的是避免将标志组合表示为String然后将其拆分。

Option A: 选项A:

public int FlagCount(System.Enum sender)
{
    bool hasFlagAttribute = sender.GetType().GetCustomAttributes(typeof(FlagsAttribute), false).Length > 0;
    if (!hasFlagAttribute) // No flag attribute. This is a single value.
        return 1;

    var resultString = Convert.ToString(Convert.ToInt32(sender), 2);
    var count = resultString.Count(b=> b == '1');//each "1" represents an enum flag.
    return count;
}

Explanation: 说明:

  • If the enum does not have a "Flags attribute", then it is bound to be a single value. 如果枚举没有“标志属性”,则它必然是单个值。
  • If the enum has the "Flags attribute", Convert it to the bit representation and count the "1"s. 如果枚举具有“标志属性”,则将其转换为位表示并计算“1”。 each "1" represents an enum flag. 每个“1”代表一个枚举标志。

Option B: 选项B:

  1. Get all flaged items. 获取所有flaged项目。
  2. Count them... 算他们......

The code: 代码:

public int FlagCount(this System.Enum sender)
{
  return sender.GetFlaggedValues().Count;
}

/// <summary>
/// All of the values of enumeration that are represented by specified value.
/// If it is not a flag, the value will be the only value returned
/// </summary>
/// <param name="value">The value.</param>
/// <returns></returns>
public static List<Enum> GetFlaggedValues(this Enum value)
{
    //checking if this string is a flagged Enum
    Type enumType = value.GetType();
    object[] attributes = enumType.GetCustomAttributes(true);

    bool hasFlags = enumType.GetCustomAttributes(true).Any(attr => attr is System.FlagsAttribute);
    //If it is a flag, add all flagged values
    List<Enum> values = new List<Enum>();
    if (hasFlags)
    {
        Array allValues = Enum.GetValues(enumType);
        foreach (Enum currValue in allValues)
        {
            if (value.HasFlag(currValue))
            {
                values.Add(currValue);
            }
        }
    }
    else//if not just add current value
    {
        values.Add(value);
    }
    return values;
}

Could not let this one go. 不能让这一个去。 Best practice when counting bits in an integer is not to convert to a string... Have we lost the ability to work with bits now we all use high level languages? 计算整数位的最佳做法是不转换为字符串...现在我们都使用高级语言,我们是否失去了使用位的能力? ;) ;)

Since the question was about the most efficient implementation, here is my answer. 由于问题是关于最有效的实施,这是我的答案。 I have not tried hyper-optimised it as to do so would confuse it I think. 我没有尝试过度优化它,因为这样做会让我感到困惑。 I have also used the previous answer as a base to make comparison easier. 我还使用前面的答案作为基础,使比较更容易。 There are two methods, one which counts the flags and one which exits early if you only want to know if it has a single flag. 有两种方法,一种用于计数标志,另一种用于提前退出,如果您只想知道它是否有一个标志。 NB: You cannot remove the flag attribute check because standard non-flag enums can be any number also. 注意:您无法删除标记属性检查,因为标准的非标记枚举也可以是任何数字。

    public static int FlagCount(this System.Enum enumValue){
        var hasFlagAttribute = enumValue.GetType().GetCustomAttributes(typeof(FlagsAttribute), false).Length > 0;
        if (!hasFlagAttribute)
            return 1;
        var count = 0;
        var value = Convert.ToInt32(enumValue);
        while (value != 0){
            if ((value & 1) == 1)
                count++;
            value >>= 1;
        }
        return count;
    }
    public static bool IsSingleFlagCount(this System.Enum enumValue){
        var hasFlagAttribute = enumValue.GetType().GetCustomAttributes(typeof(FlagsAttribute), false).Length > 0;
        if (!hasFlagAttribute)
            return true;
        var isCounted = false;
        var value = Convert.ToInt32(enumValue);
        while (value != 0){
            if ((value & 1) == 1){
                if (isCounted)
                    return false;
                isCounted = true;
            }
            value >>= 1;
        }
        return true;
    }

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM