2009-02-27 3 views
15

私のチームは最近、コーディング基準の統合の出発点としてLance Hunt's C# Coding Standards文書の使用を開始しました。ランスハントのC#コードの標準 - enumの混乱

私たちはちょうどそのポイントを理解していない1つの項目があります。

が常に消費 前に列挙変数またはパラメータ値を検証:

アイテムは数77です。基になる列挙型 (既定のint)がサポートする任意の 値を含むことがあります。

例:

public void Test(BookCategory cat) 
{ 
if (Enum.IsDefined(typeof(BookCategory), cat)) 
{…} 
} 

答えて

13

私は上記のコメントがかなり答えたと思います。本質的に、私がこのルールを書いたとき、私はすべての入力を検証する防御的なコーディング慣行を伝えようとしていました。列挙型は特別なケースです。なぜなら、多くの開発者は、検証されていないときに検証されると誤って想定しているからです。結果として、定義されていないenum値に対して、ステートメントまたはswitchステートメントが失敗することがよくあります。

デフォルトでは、enumはINTの周りのラッパーにすぎず、まるでintのように検証します。適切な列挙型の使用方法のより詳細な議論については

、あなたはブラッドエイブラムスとクシシュトフ・クワリーナまたはそれらの優れた本を読んでブログ記事をチェックアウトすることがあります

17

列挙型はチェックされません。

enum Foo { A= 1, B = 2, C = 3} 
Foo x = (Foo) 27; // works fine 

は今、あなたが定義されていないFooを持っています。 彼はちょうど "あなたの入力を確認する"と言っています。 Enum.IsDefinedは比較的遅い(リフレクションベース)。個人的に、私は例外をスローdefaultでスイッチを使用する傾向がある:

switch(x) { 
    case Foo.A: /* do something */ break; 
    case Foo.B: /* do something */ break; 
    case Foo.C: /* do something */ break; 
    default: throw new ArgumentOutOfRangeException("x"); 
} 
+0

「フレームワークの設計ガイドラインの再利用可能な.NETライブラリのための規則、慣用句、およびパターン」私はあなたが常にデフォルトを持っていることに同意します:新しいArgumentOutOfRangeExceptionをスローします。また、新しい値が列挙に追加されるシナリオについても説明します。 –

+2

おそらく、NotSupportedExceptionがより適切かもしれません。 –

+2

合意!新しいOldShoeException()を投げることは、ロジックを落とさせることと、結果として他の場所に現れるバグを引き起こすことよりも優れています。 –

1

それはこのようことを「テスト」メソッドを呼び出すために、完全に法的ですので、これは次のとおりです。キャストだろうと

Test((BookCategory)-999); 

-999をBookCategoryとして使用しますが、結果(Testに "cat"パラメータとして渡される)はBookCategory列挙体の有効な値ではありません。

+0

私はあなたが "それはキャスト-999"を意味すると思う... –

+0

おっと、あなたはそうです - 私は戻って、編集し、ポストの一部を編集したが、他の部分を変更するのを忘れてしまった。ありがとう! –

20

BookCategoryタイプのパラメータを使用すると、の書籍カテゴリには、常にの意味があることを願っています。そうではありません。私は呼び出すことができます。

BookCategory weirdCategory = (BookCategory) 123456; 
Test(weirdCategory); 

を列挙は、値のよく知られたセットを表すように意図されている場合は、コードが賢明ことはよく知られたセット以外の値を処理するために期待するべきではありません。テストでは、引数が適切かどうかが最初にチェックされます。

私は個人的にかかわらず、論理を反転したい:

使用:

public void Test(BookCategory cat) 
{ 
    cat.ThrowIfNotDefined("cat"); 
} 
+2

ジェネリックスが制約として "Enum"/"enum"を許可しないという痛みです... –

+0

@Marc:確かに。 @リチャード:追加されました。 –

+0

恥知らずのプラグイン:私のヘルパートリニティユーティリティクラスには、列挙を含む引数をチェックする拡張メソッドが含まれています。 http://thehelpertrinity.codeplex.com/Wiki/View.aspx?title=wiki%20documentation&referringTitle=Home#AssertEnumMember –

1

場合はC#3本で

public void Test(BookCategory cat) 
{ 
    if (!Enum.IsDefined(typeof(BookCategory), cat)) 
    { 
     throw new ArgumentOutOfRangeException("cat"); 
    } 
} 

を容易に拡張する方法で行うことができますあなたのライブラリの将来のバージョンであなたの列挙型を新しい値で拡張したい場合は、構造体を使用しないでください (Enum.IsDefined(typeof演算(BookCategory)、ネコ))型が列挙定義に従って有効であるかどうかをこののみテストとして

場合。一方、あなたのコードは現在許容されている値に対してのみテストされ、新しい値では失敗する可能性があります。

詳細については、This weblog articleを参照してください。

+0

列挙型で定義されていない列挙型、最初に列挙型を持つ点は何ですか? –

+0

ポイントは、後で(コードを再コンパイルすることによって)新しい有効な列挙型の値を定義できるということです。この新しい値でテストされなかった... Enum.IsDefinedは真を返す –