Enumは0または1で始まる必要がありますか?


136

次のEnumを定義したとしましょう。

public enum Status : byte
{
    Inactive = 1,
    Active = 2,
}

列挙型を使用するためのベストプラクティスは何ですか?1上記の例のように開始するか、次のように0(明示的な値なしで)開始する必要があります。

public enum Status : byte
{
    Inactive,
    Active
}

13
本当に明示的に番号を付ける必要がありますか?
Yuck

164
列挙型は、このようなことが重要ではないように作成されました。
BoltClock

9
@ダニエル-いえいえ!列挙型のことを考えているときにブール値を使用するよりも、ブール値を使用すると考える場合に列挙型を使用する方が適切です。
AAT 2011

22
もちろん、FileNotFound値のため、ダニエル
Joubarc

5
xkcd.com/163は、配列のインデックスよりもさらに列挙型に適用されます。
leftaroundabout '08

回答:


161

フレームワーク設計ガイドライン

simple️単純な列挙型ではゼロの値を提供します。

「なし」などの値を呼び出すことを検討してください。そのような値がこの特定の列挙型に適切でない場合は、列挙型の最も一般的なデフォルト値に、基礎となるゼロの値を割り当てる必要があります。

フレームワーク設計ガイドライン/フラグ列挙の設計

flag値が「すべてのフラグがクリアされている」ことを表し、次のガイドラインで規定されているように適切に名前が付けられていない限り、ゼロのフラグ列挙値を使用しないでください。

✔️フラグ列挙型のゼロ値にNoneと名前を付けます。フラグ列挙型の場合、値は常に「すべてのフラグがクリアされている」ことを意味する必要があります。


28
早期に失敗する: 'None'が適切ではないが論理的なデフォルト値がない場合でも、使用することを意図していないゼロの値を(それを 'None'または 'Invalid'と呼びます)設定します。その列挙のクラスメンバーが適切に初期化されていない場合、初期化されていない値は簡単に見つかる可能性があり、switchステートメントでは、defaultセクションにジャンプしてをスローしInvalidEnumArgumentExceptionます。そうしないと、プログラムが意図せずに列挙のゼロ値で実行を継続する場合があります。これは有効であり、気付かれない可能性があります。
Allon Guralnek、2011

1
@Allon有効であることがわかっている列挙値のみを指定し、セッターやコンストラクターで無効な値をチェックすることをお勧めします。こうすることで、無効なデータを含むオブジェクトを未知の時間存在させ、後でそれを見つけるのではなく、コードが正しく機能していないかどうかをすぐに知ることができます。「なし」が有効な状態を表していない限り、使用しないでください。
wprl 2011

@SoloBold:コンストラクターで列挙型クラスメンバーを初期化することを忘れない場合のように聞こえます。初期化を忘れたり、検証を忘れたりした場合、検証の量は役に立ちません。また、コンストラクターを持たず、代わりにオブジェクト初期化子に依存する単純なDTOクラスもあります。このようなバグを追い詰めることは、非常に苦痛なことです。それにもかかわらず、未使用の列挙値を追加すると、醜いAPIになります。公共消費向けのAPIの場合は、これを避けます。
Allon Guralnek、2011

@Allonそれは良い点ですが、セッターが呼び出されたことがない場合は、セッター関数の列挙型を検証し、ゲッターからスローする必要があると私は主張します。そうすることで、1つの障害点があり、常に有効な値を持つフィールドを計画できるため、設計とコードが簡素化されます。とにかく私の2セント。
wprl 2011

@SoloBold:15の自動実装プロパティを持つDTOクラスを想像してください。体は15行です。通常のプロパティを持つ同じクラスを想像してください。これは、検証ロジックを追加する前の最小180行です。このクラスは、データ転送の目的でのみ内部的にのみ使用されます。15行クラスと180行以上のクラスのどちらを維持しますか?簡潔さには価値があります。しかし、それでも、私たちのスタイルはどちらも正しいです。それらは単に異なるだけです。(私はこれがAOPが一掃し、議論の両面を獲得するところだと思います)。
Allon Guralnek、2011

66

まあ、私はそれらに明示的に番号を付けないように言うほとんどの答えに同意しないと思います。私は常に明示的に番号を付けていますが、それはほとんどの場合、整数値として格納されているデータストリームにそれらを永続化することになるためです。値を明示的に追加せずに新しい値を追加すると、シリアル化が中断され、古い永続化オブジェクトを正確にロードできなくなります。これらの値を永続的に保存する場合は、値を明示的に設定することを強くお勧めします。


9
+1、同意。ただし、コードが何らかの外部的な理由(たとえば、シリアル化)のために整数に依存している場合のみ。それ以外の場所では、フレームワークに仕事を任せるだけです。内部で整数値に依存している場合は、おそらく何かが間違っています(参照:フレームワークに任せてください)。
Matthew Scharley、2011

3
列挙型のテキストを保持するのが好きです。データベースをはるかに使いやすいimoにします。
Dave、

2
通常、値を明示的に設定する必要はありません...シリアル化された場合でもです。常に最後に新しい値を追加してください。これにより、シリアル化の問題が解決します。それ以外の場合は、データストアのバージョニング(たとえば、値の読み取り/書き込み時の動作を変更するためのバージョンを含むファイルヘッダー)が必要になる場合があります(またはmementoパターンを参照)
Beachwalker

4
@Dave:列挙型のテキストが神聖であるという明確な文書でない限り、将来のプログラマーが名前をより明確にしたり、いくつかの命名規則に準拠したりすることを決定した場合、失敗するように設定します。
スーパーキャット2011

1
@pstrjds:それはスタイルのトレードオフだと思います-ディスクスペースは安いですが、dbを検索するときにenum値とintの間で絶えず変換するのに費やされる時間は比較的高価です(データベースに対してレポートツールを設定している場合など) 。スペースを心配している場合は、新しいSQLサーバーバージョンでデータベースを圧縮できます。つまり、「SomeEnumTextualValue」が1000回発生しても、ほとんどスペースを使用しません。もちろん、これはすべてのプロジェクトで機能するわけではありません-それはトレードオフです。帯域幅の問題は、時期尚早の最適化のようなものだと思います。
Dave

15

Enumは値の型であり、明示的に初期化されていない場合、そのデフォルト値(クラスのEnumフィールドなど)は0になります。

したがって、一般的には、定義された定数(たとえば、不明)として0が必要です。

あなたの例では、あなたInactiveがデフォルトになりたいなら、それはゼロの値を持つべきです。それ以外の場合は、定数を追加することを検討してくださいUnknown

定数の値を明示的に指定しないことを推奨する人もいます。ほとんどの場合はおそらく良いアドバイスですが、そうしたい場合もいくつかあります。

  • フラグ列挙型

  • 値が外部システム(COMなど)との相互運用で使用される列挙型。


値を明示的に設定しない場合は、フラグ列挙型の方がずっと読みやすいことわかりました。-また、コンパイラーにバイナリー計算を行わせるためにエラーが発生しにくくなります。(つまり[Flags] enum MyFlags { None = 0, A, B, Both = A | B, /* etc. */ }、より読みやすくなり[Flags] enum MyFlags { None = 0, A = 1, B = 2, Both = 3, /* etc */ }ます。)
BrainSlugs83

1
@ BrainSlugs83-それが一般的な場合にどのように役立つかわかりません-たとえば、[Flags] enum MyFlags { None=0, A, B, C } 結果[Flags] enum MyFlags { None=0, A=1, B=2, C=3 }はになりますが、Flags列挙型の場合、通常はC = 4が必要です。
Joe

14

変更する特別な理由がない限り、列挙型はデフォルト値(ゼロから始まる)のままにしておきます。

public enum Status : byte
{
    Inactive,
    Active
}

6

私はベストプラクティスはそれらに番号を付けないことであり、それを暗黙的にすることです-それは0から始まります。その暗黙的であるため、常に従うのが良い言語設定です:)


6

私はブール型の列挙を0で始めます。

「ネイティブ」が「非アクティブ」以外のものを意味しない限り:)

これはそれらのための標準を保持します。


6

どういうふうに使うかによりますね。enumにフラグを立てる場合はNone、次のように値に0を設定することをお勧めします。

[Flags]
enum MyEnum
{
    None = 0,
    Option1 = 1,
    Option2 = 2,
    Option3 = 4,
    All = Option1 | Option2 | Option3,
}

列挙型がデータベースルックアップテーブルにマップされる可能性がある場合は、1から始めます。プロが作成したコードではそれほど問題になりませんが、これにより読みやすさが向上します。

それ以外の場合はそのままにしておき、0と1のどちらで始まるかを気にしません。


5

未加工の値を使用する十分な理由がない限り、暗黙の値のみを使用し、Status.Activeおよびでそれらを参照する必要がありStatus.Inactiveます。

問題は、フラットファイルまたはDBにデータを保存するか、他のユーザーが作成したフラットファイルまたはDBを使用することです。自分で作成する場合は、番号付けがEnumの用途に合うようにしてください。

データが自分のものでない場合は、もちろん、元の開発者が番号付けスキーマとして使用していたものをすべて使用することになります。

Enumをフラグのセットとして使用することを計画している場合、以下の価値がある簡単な規則があります。

enum Example
{
  None      = 0,            //  0
  Alpha     = 1 << 0,       //  1
  Beta      = 1 << 1,       //  2
  Gamma     = 1 << 2,       //  4
  Delta     = 1 << 3,       //  8
  Epsilon   = 1 << 4,       // 16
  All       = ~0,           // -1
  AlphaBeta = Alpha | Beta, //  3
}

値は2のべき乗である必要があり、ビットシフト演算を使用して表現できます。None、明らかにする必要がありますが0Allそれほど明白ではありません-1~0バイナリの否定である0にすべてのビット設定した数で、その結果1の値を表します-1。複合フラグ(便宜上よく使用される)の場合、他の値はビットごとのor演算子を使用してマージできます|


3

番号を割り当てないでください。本来の使用方法でご使用ください。


3

指定されていない場合、番号付けは0から始まります。

enumは文字列ではなくシリアル化されてintとして保存されることが多いため、明示することが重要です。

データベースに保存されている列挙型については、メンテナンス中のシフトと再割り当てを防ぐために、常に明示的にオプションに番号を付けます。

Microsoftによれば、推奨される規則は、最初のゼロオプションを使用して、初期化されていない、または最も一般的なデフォルト値を表すことです。

以下は、番号付けを0ではなく1から開始するためのショートカットです。

public enum Status : byte
{
    Inactive = 1,
    Active
}

列挙値にビット演算子を使用するためにフラグ値を設定する場合は、ゼロ値から番号付けを開始しないでください。


2

1から始めれば、簡単に数を数えることができます。

{
    BOX_THING1     = 1,
    BOX_THING2     = 2,
    BOX_NUM_THING  = BOX_THING2
};

0から始める場合は、最初の値を初期化されていないものの値として使用します。

{
    BOX_NO_THING   = 0,
    BOX_THING1     = 1,
    BOX_THING2     = 2,
    BOX_NUM_THING  = BOX_THING2
};

5
申し訳ありません、ジョナサン。私は、この提案は私の頭の中では少し「古い学校」だと思います(ある種の慣習は低学年から来ています)。これは、列挙型に関するいくつかの追加情報を「埋め込む」ための迅速な解決策としては問題ありませんが、大規模なシステムではお勧めできません。利用可能な値の数などの情報が必要な場合は、列挙型を使用しないでください。BOX_NO_THING1はどうですか?彼にBOX_NO_THING + 1をあげますか?列挙型は、次の用途に使用する必要があります。「話す」名前で表される特定の(int)値。
Beachwalker、2011

うーん。MicrosoftBumpyCaseWithLongNamesではなく、すべて大文字を使用したので、それは古い学校だと思っています。列挙されたXyzNumDefsInMyEnum定義に到達するまで、ループよりもイテレータを使用する方がよいことに同意します。
ジョナサンクラインIEEE

これは、さまざまな点でC#でのひどい習慣です。これで、列挙のカウントを正しい方法で取得するとき、または列挙を正しい方法で列挙しようとすると、余分な重複オブジェクトが取得されます。また、とりわけ、.ToString()呼び出しが曖昧になる可能性があります(最新のシリアライゼーションを増やす)。
BrainSlugs83 2016年

0

まず、理由のために特定の値を指定している場合を除き(数値は他の場所、つまりデータベースや外部サービスに意味があります)、数値をまったく指定せず、明示的に指定します。

第二に、常にゼロ値のアイテム(非フラグ列挙型)が必要です。その要素がデフォルト値として使用されます。


0

配列やリストのインデックスとして使用するなどの理由がない限り、または他の実用的な理由(ビット単位の演算で使用するなど)がある場合以外は、0から開始しないでください。

あなたenumはそれが必要なところから正確に始めるべきです。順次である必要もありません。値が明示的に設定されている場合は、意味的な意味や実際の考慮事項を反映する必要があります。たとえばenum、「壁のボトル」には1〜99の番号を付け、enum、4の累乗の場合は、4から始めて16、64、256などにする必要があります。

さらに、ゼロ値要素をに追加するenumことは、それが有効な状態を表す場合にのみ行う必要があります。「なし」、「不明」、「欠落」などが有効な値の場合もありますが、そうでない場合もあります。


-1

私は列挙型を0から開始するのが好きです。これがデフォルトですが、値-1の不明な値を含めることも好きです。これがデフォルトになり、デバッグに役立つことがあります。


4
恐ろしい考え。値型として、列挙型は常にゼロに初期化されます。不明または初期化されていないことを表す値がある場合は、0にする必要があります。デフォルトを-1に変更することはできません。ゼロフィルはCLR全体でハードコード化されています。
Ben Voigt

ああ、気づかなかった。私は通常、デカール/初期化するときに列挙値/プロパティの値を設定します。ポインタをありがとう。
トーマスマクギネス
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.