3

私はそのように定義された列挙型を持っています:

[Flags]
public enum Orientation
{
    North = 1,
    North_East = 2,
    East = 4,
    South_East = 8,
    South = 16,
    South_West = 32,
    West = 64,
    North_West = 128
}

複数のフラグが設定されているか、フラグが設定されていないかを確認する一般的な方法はありますか? 列挙型の値は気にしません。設定されているフラグの数を知りたいだけです。

これは、ビット数をカウントするための複製ではありません。このように列挙型を初期化し、ビット数をカウントすると、10 になります。しかし、設定されたフラグの数は 8 になります。

GeographicOrientation go = (GeographicOrientation) 1023;
4

6 に答える 6

3
var test = Orientation.North;
var flagCount = GetFlagCount(test);

public int GetFlagCount(Enum testValue)
{
    return Enum.GetValues(testValue.GetType()).Cast<Enum>().Count(testValue.HasFlag);
}
于 2016-06-13T17:30:12.680 に答える
2

「最短」の方法を探している場合:

Orientation o = Orientation.East | Orientation.West;   // o.ToString() = "East, West"
var c = o.ToString().Split().Count(); 

またはさらに短い:

var c = (o + "").Split().Count(); 

アップデート

255 を超える値をサポートするには、これらの醜いハックのいずれかを使用できます。

Orientation o = (Orientation) 1023;   
var c = ((Orientation)(byte)o + "").Split().Count();
c = ((Orientation)((int)o & 255) + "").Split().Count();

または単に列挙型をバイトとして定義します。

    [Flags]
    public enum Orientation : byte
    {
        North = 1,
        North_East = 2,
        East = 4,
        South_East = 8,
        South = 16,
        South_West = 32,
        West = 64,
        North_West = 128
    }

更新 2 個人的には、特にビット カウントが必要な場合は、プロダクション コードで string メソッドを使用しません。

とにかく、私はちょうど楽しみのために別のハックを考えました. 基数 2 のログは、1 ビットが設定されている場合は整数を返し、0 の場合は -Infinity を返し、複数のビットが設定されている場合はそれ以外を返します。例えば

 Math.Log(0, 2 ) // -Infinity
 Math.Log(0, 64) // 6.0
 Math.Log(0, 65) // 6.0223678130284544

そのため、(byte)go != 0フラグが設定されているかどうかを確認してから、フラグが 1 つだけ設定されているかどうかを確認するために使用できますMath.Log((byte)go, 2) % 1 == 0

しかし、dasblinkenlight のソリューションが最善のようです。

于 2016-06-13T17:51:52.840 に答える
1

私の頭の上から:

var map = 1;
var count = 0;

while (map <= North_West)
{
    if( ((int)Value & map) > 0) 
       count += 1; 
    map = map << 1; //left shift, a.k.a. multiply by 2
}
于 2016-06-13T17:25:43.677 に答える
0

これは、ビット数をカウントするための複製ではありません。このように列挙型を初期化し、ビット数をカウントすると、10 になります。しかし、設定されたフラグの数は 8 になります。

MSDN から直接この声明を検討してください。

フラグ列挙は、ビット フィールドのマスキングとビットごとの比較に使用されます。

ビット演算を使用してフラグの数をカウントできないような方法で列挙型を設計または使用している場合は、列挙型を不適切に設計または使用しています。

    [Flags]
    public enum MyEnum
    {
        Foo = 1,
        Bar = 2,
        Bizz = 4,
        Buzz = 8,
        Boo = 16
    }


var foo = MyEnum.Foo | MyEnum.Foo | MyEnum.Bizz;
// foo == MyEnum.Foo | MyEnum.Bizz because setting the same flag twice does nothing

var bar = (MyEnum)27 // Some invalid combination
// bar == 27.  Why would you do this instead of MyEnum.Boo | MyEnum.Buzz | MyEnum.Bar | MyEnum.Foo

列挙型を適切に設計すると、フラグをカウントできます。また、カウントを続けても意味がないため、複数のフラグが設定されている場合はオプションで短絡できます。

        var foo = MyEnum.Foo | MyEnum.Bizz;
        int fooValue = (int)foo;
        int numberOfFlags = 0;

        while (fooValue > 0 && numberOfFlags < 2) // Stop counting if more than one flag since we don't need exact count
        {
            if ((fooValue & 1) == 1)
            {
                numberOfFlags++;
            }

            fooValue >>= 1;
        }

        Console.WriteLine(numberOfFlags);
于 2016-06-13T18:00:54.427 に答える