なぜ人々はいつものように列挙値を使用していません0, 1, 2, 4, 8
か0, 1, 2, 3, 4
?
これはビット操作などと関係がありますか?
これが正しく使用される方法に関する小さなサンプルスニペットを本当に感謝します:)
[Flags]
public enum Permissions
{
None = 0,
Read = 1,
Write = 2,
Delete = 4
}
なぜ人々はいつものように列挙値を使用していません0, 1, 2, 4, 8
か0, 1, 2, 3, 4
?
これはビット操作などと関係がありますか?
これが正しく使用される方法に関する小さなサンプルスニペットを本当に感謝します:)
[Flags]
public enum Permissions
{
None = 0,
Read = 1,
Write = 2,
Delete = 4
}
回答:
彼らは2の累乗であり、私はこれを行うことができるので:
var permissions = Permissions.Read | Permissions.Write;
そしておそらく後で...
if( (permissions & Permissions.Write) == Permissions.Write )
{
// we have write access
}
これはビット・フィールドであり、設定された各ビットは何らかの許可(または列挙値が論理的に対応するものは何でも)に対応します。これらが定義されている1, 2, 3, ...
場合、この方法でビット演算子を使用して意味のある結果を得ることができません。より深く掘り下げるには...
Permissions.Read == 1 == 00000001
Permissions.Write == 2 == 00000010
Permissions.Delete == 4 == 00000100
ここにパターンに気づきましたか?ここで、元の例、つまり
var permissions = Permissions.Read | Permissions.Write;
その後...
permissions == 00000011
見る?両方Read
とWrite
ビットが設定され、そして私は、独立して確認することができる(ようにしても通知Delete
ビットがされていない設定を、したがって、この値は削除する権限を伝達しません)。
これにより、ビットの単一フィールドに複数のフラグを格納できます。
myEnum.IsSet
。これは完全に役に立たない抽象化であり、タイピングを削減するためにのみ役立つと私は思うが、まあ
Flags
属性は「きれいな印刷」を提供するだけです。属性の存在に関係なく、列挙値をフラグとして使用できます。
0
ないfalse
; false
ですfalse
。しかし、あなたは書くことができますif((permissions & Permissions.Write) > 0)
。
(permissions & Permissions.Write) == Permissions.Write
現在使用できますenum.HasFlag()
それでも他の回答から明確でない場合は、次のように考えてください。
[Flags]
public enum Permissions
{
None = 0,
Read = 1,
Write = 2,
Delete = 4
}
書くためのより短い方法です:
public enum Permissions
{
DeleteNoWriteNoReadNo = 0, // None
DeleteNoWriteNoReadYes = 1, // Read
DeleteNoWriteYesReadNo = 2, // Write
DeleteNoWriteYesReadYes = 3, // Read + Write
DeleteYesWriteNoReadNo = 4, // Delete
DeleteYesWriteNoReadYes = 5, // Read + Delete
DeleteYesWriteYesReadNo = 6, // Write + Delete
DeleteYesWriteYesReadYes = 7, // Read + Write + Delete
}
8つの可能性がありますが、4つのメンバーのみの組み合わせとして表すことができます。16の可能性がある場合、それらを5つのメンバーのみの組み合わせとして表すことができます。40億の可能性がある場合は、33のメンバーのみの組み合わせとして表すことができます。列挙型で40億個のアイテムに名前を付けるよりも、33のメンバー(それぞれ0を除く)を2の累乗にするほうがはるかに優れています。
enum
メンバーが40億人いるメンタルイメージの場合は+1 。そして悲しい部分は、おそらく誰かがそれを試したことがあるでしょう。
2 ** -infinity
2の累乗として数えない限り)。
これらの値はバイナリの一意のビット位置を表すため、次のようになります。
1 == binary 00000001
2 == binary 00000010
4 == binary 00000100
など
1 | 2 == binary 00000011
編集:
3 == binary 00000011
2進数の3は、1の場所と2の場所の両方で値1によって表されます。実際には値と同じです1 | 2
。したがって、バイナリの場所をフラグとして使用して状態を表す場合、3は通常意味がありません(実際には2つの組み合わせである論理値がない限り)。
さらに明確にするために、例の列挙型を次のように拡張することもできます。
[Flags]
public Enum Permissions
{
None = 0, // Binary 0000000
Read = 1, // Binary 0000001
Write = 2, // Binary 0000010
Delete = 4, // Binary 0000100
All = 7, // Binary 0000111
}
したがって、私が持っている中でPermissions.All
、私はまた、暗黙のうちに持っているPermissions.Read
、Permissions.Write
と、Permissions.Delete
3
は11
バイナリであるため、つまり単一のセットビットにマップされないため、任意の位置の1ビットを意味のある値にマップする機能を失います。
2|3 == 1|3 == 1|2 == 3
。あなたがバイナリで値を持っているのであれば00000011
、そしてあなたのフラグが値を含め1
、2
、及び3
、その後、あなたはその値が表す場合は知っているだろう1 and 3
、2 and 3
、1 and 2
またはonly 3
。そのため、あまり役に立たなくなります。
これらは、列挙値の組み合わせを可能にするビットフラグを表すために使用されます。値を16進表記で記述した方がわかりやすいと思います
[Flags]
public Enum Permissions
{
None = 0x00,
Read = 0x01,
Write = 0x02,
Delete= 0x04,
Blah1 = 0x08,
Blah2 = 0x10
}
4194304
2 を掛けると何が得られますか?いかが0x400000
ですか?0x800000
は正解として認識する方がはるかに簡単8388608
です。また、16進値を入力することでエラーが発生しにくくなります。
0x10000
2のべき乗では?はい、1、2、4、または8で始まり、その後すべて0になります。精神的に0x10を16に変換する必要はありません(そうすることで、最終的には2番目の性質になるでしょう)、それを「2のべき乗」と考えてください。
これは実際にはもっとコメントですが、それはフォーマットをサポートしないので、フラグ列挙を設定するために採用したメソッドを含めたかっただけです:
[Flags]
public enum FlagTest
{
None = 0,
Read = 1,
Write = Read * 2,
Delete = Write * 2,
ReadWrite = Read|Write
}
このアプローチは、フラグをアルファベット順に維持したい場合に、開発中に特に役立ちます。新しいフラグ値を追加する必要があると判断した場合は、それをアルファベット順に挿入するだけでよく、変更する必要がある唯一の値は、その前の値です。
ただし、ソリューションがプロダクションシステムに公開されると(特に、列挙がWebサービスなどの密結合なしに公開される場合)、列挙内の既存の値を変更しないことを強くお勧めします。
これに対する良い答えはたくさんあります...言いたいことは..気に入らない場合、または構文が表現しようとしていることを簡単に理解できない場合<<
..私は個人的に代替案を好みます(そして、あえて言うと、単純な列挙型宣言スタイル) …
typedef NS_OPTIONS(NSUInteger, Align) {
AlignLeft = 00000001,
AlignRight = 00000010,
AlignTop = 00000100,
AlignBottom = 00001000,
AlignTopLeft = 00000101,
AlignTopRight = 00000110,
AlignBottomLeft = 00001001,
AlignBottomRight = 00001010
};
NSLog(@"%ld == %ld", AlignLeft | AlignBottom, AlignBottomLeft);
LOG 513 == 513
理解するのがとても簡単になりました(少なくとも私にとっては)。必要な結果を記述し、必要な結果を取得してください。「計算」は必要ありません。