8

編集:ほとんどの人が私の質問を誤解しているようです.

私は列挙型がどのように機能するかを知っており、バイナリも知っています。[Flags] 属性を持つ列挙型がそのように設計されている理由が不思議です。

元の投稿:

これは重複している可能性がありますが、他の投稿が見つからなかったので、ここに行きます.

その背後には何らかの正当な理由があるに違いありませんが、少しバグが発生しやすいと思います。

[Flag]
public enum Flagged
{
  One, // 0
  Two, // 1
  Three, // 2
  Four, // 3
}

Flagged f; // Defaults to Flagged.One = 0
f = Flagged.Four;
(f & Flagged.One) != 0; // Sure.. One defaults to 0
(f & Flagged.Two) != 0; // 3 & 1 == 1
(f & Flagged.Three) != 0; // 3 & 2 == 2

このようなことをしたら、もっと意味があったのではないでしょうか?

[Flag]
public enum Flagged
{
  One = 1 << 0, // 1
  Two = 1 << 1, // 2
  Three = 1 << 2, // 4
  Four = 1 << 3, // 8
}

Flagged f; // Defaults to 0
f = Flagged.Four;
(f & Flagged.One) != 0; // 8 & 1  == 0
(f & Flagged.Two) != 0; // 8 & 2 == 0
(f & Flagged.Three) != 0; // 8 & 4 == 0
(f & Flagged.Four) != 0; // 8 & 8 == 8

もちろん..このようなカスタムフラグをどのように処理する必要があるかはよくわかりません

[Flag]
public enum Flagged
{
   One, // 1
   Two, // 2
   LessThanThree = One | Two,
   Three, // 4? start from Two?
   LessThanFour = Three | LessThanThree,
   Three, // 8? start from Three?
}

仕様はいくつかのガイドラインを提供します

2 の累乗、つまり 1、2、4、8 などで列挙定数を定義します。これは、組み合わせた列挙定数の個々のフラグが重複しないことを意味します。

しかし、私の最初の例が発生することを決して望んでいないに違いないので、これはおそらく自動的に行われるべきです。教えてください:)

4

6 に答える 6

13

このFlags属性は、値を複数の値としてフォーマットするためにのみ使用されます。ビット操作は、属性の有無にかかわらず、基になる型で機能します。

于 2010-06-24T17:10:44.620 に答える
7

明示的に他の値を指定しない限り、列挙の最初の項目はゼロです。「フラグなし」または「オフ」などのゼロ値にセマンティックな意味を提供するため、フラグ列挙にゼロ値を設定することがベスト プラクティスであることがよくあります。これは、コードの意図を暗示できるため、コードを維持するのに役立ちます (ただし、コメントもこれを実現します)。

それ以外では、ゼロ値が必要かどうかは、実際にはあなたとあなたのデザイン次第です。

フラグ列挙は依然として単なる列挙であるため ( はFlagsAttribute、値を他の値の組み合わせとして解釈するようにデバッガーに指示するだけです)、列挙の次の値は常に前の値よりも 1 大きくなります。したがって、組み合わせを他の値のビットごとの OR として表現したい場合があるため、ビット値を明示的に指定する必要があります。

とはいえ、すべてのビット単位の組み合わせを列挙定義の最後に配置するか、何らかの方法でマークすることを要求するフラグ列挙の構文を想像するのは不合理ではありません。これにより、コンパイラは他のすべての処理方法を認識できます。

たとえば (flagsキーワードがあり、現在北半球にいると仮定して)、

flags enum MyFlags
{
   January,
   February,
   March,
   April,
   May,
   June,
   July,
   August,
   September,
   October,
   November,
   December,
   Winter = January | February | March
   Spring = April | May | June
   Summer = July | August | September
   Autumn = October | November | December
} 

この構文を使用すると、コンパイラは値 0 自体を作成し、フラグを他の値に自動的に割り当てることができます。

于 2010-06-24T17:05:27.613 に答える
6

属性は【フラグ】ではなく【フラグ】で、魔法のようなものは何もありません。影響しているように見える唯一のものは、ToString メソッドです。[Flags] を指定した場合、値はカンマ区切りで出力されます。ビット フィールドでの使用を有効にする値を指定するのは、ユーザー次第です。

于 2010-06-24T17:13:01.940 に答える
4

注釈付きの C# 3 仕様には何もありません。注釈付きの C# 4 仕様に何かあると思いますが、よくわかりません。(私は自分でそのような注釈を書き始めたと思いますが、その後削除しました。)

単純なケースでは問題ありませんが、追加のフラグを追加し始めるとすぐに、少し注意が必要になります。

[Flags]
enum Features
{
    Frobbing, // 1
    Blogging, // 2 
    Widgeting, // 4
    BloggingAndWidgeting = Frobbing | Blogging, // 6
    Mindnumbing // ?
}

Mindnumbing にはどのような価値がありますか? 使用されていない次のビットは?固定整数値を設定するとどうなりますか?

これが苦痛であることには同意します。合理的ないくつかのルールを解決できるかもしれませんが、複雑さと価値のバランスが本当にうまくいくかどうかは疑問です。

于 2010-06-24T17:12:49.553 に答える
2

簡単に言えばFlags属性です。列挙が作成されるまで適用されないため、列挙に割り当てられた値は変更されません。

そうは言っても、MSDNページDesigning Flags Enumerationsには次のように書かれています:

フラグ列挙の値には 2 のべき乗を使用して、ビットごとの OR 演算を使用して自由に組み合わせることができるようにします。

重要: 2 の累乗または 2 の累乗の組み合わせを使用しない場合、ビット演算は期待どおりに機能しません。

同様に、のページはFlagsAttribute言う

2 の累乗、つまり 1、2、4、8 などで列挙定数を定義します。これは、組み合わせた列挙定数の個々のフラグが重複しないことを意味します。

于 2010-06-24T18:20:02.617 に答える
0

Cでは、プリプロセッサを(ab)使用して、2の累乗の列挙を自動的に生成することができます。「make_thing(flag1)make_thing(flag2)make_thing(flag3)」などに展開されるマクロmake_thingsがある場合、2の累乗を達成するために、make_thingの異なる定義を使用してそのマクロを複数回呼び出すことができます。一連の旗の名前とその他のグッズ。

たとえば、make_thing(x)を "LINEAR_ENUM _ ## x"(コンマを含む)として定義することから始め、次にenumステートメントを使用して列挙型のリストを生成します(make_thingsマクロの外部のLINEAR_NUM_ITEMSを含む)。次に、別の列挙型を作成します。今回は、make_thing(x)を「FLAG_ENUM _ ## x =1<」として定義します。

むしろ、フラグと線形値が自動的に同期された状態で、そのように実行できるいくつかの気の利いたものです。コードは「if(thingie [LINEAR_ENUM_foo] things_errors | = FLAG_ENUM_foo;」(線形値とフラグ値の両方を使用)のような優れた処理を実行できます。残念ながら、C#またはVB.netでリモートで同様の処理を実行する方法はわかりません。

于 2010-06-24T18:30:27.320 に答える