4

いくつかのシナリオでは、Enum をメソッドに渡すときに、それが単一の Enum 値であるか、それ以外の場合はフラグの組み合わせであるかを処理する必要があります。その目的のために、次の単純な拡張機能を作成しました。

Vb.Net:

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

C# (オンライン翻訳):

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

使用例:

Vb.Net:

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

C# (オンライン翻訳):

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

フラグの組み合わせを文字列として表し、それを分割することを避けるために現在行っている、より直接的で効率的な方法が存在するかどうかを尋ねたいだけです。

4

2 に答える 2

6

オプション 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;
}

説明:

  • 列挙型に「Flags 属性」がない場合は、単一の値にバインドされます。
  • 列挙型に「Flags 属性」がある場合は、ビット表現に変換して「1」を数えます。各「1」は列挙型フラグを表します。

オプション B:

  1. フラグが立てられたすべてのアイテムを取得します。
  2. それらを数える...

コード:

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;
}
于 2016-05-01T06:05:04.980 に答える
0

これは手放せませんでした。整数のビット数を数える際のベスト プラクティスは、文字列に変換しないことです...現在、高水準言語を使用するようになった今、ビットを扱う能力を失ったのでしょうか? ;)

質問は最も効率的な実装に関するものだったので、これが私の答えです。私はそれを混乱させるので、超最適化を試みていません。また、比較を容易にするために、前の回答をベースとして使用しました。2 つの方法があります。1 つはフラグをカウントする方法で、もう 1 つはフラグが 1 つだけかどうかだけを知りたい場合に早期に終了する方法です。注意: 標準の非フラグ列挙型も任意の数になる可能性があるため、フラグ属性チェックを削除することはできません。

    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;
    }
于 2017-05-13T21:40:19.673 に答える