2012-02-24 17 views
3

(主に通信プロトコル、)組み込みのAPIを扱うときに、私は多くの場合、Cで使用したショートカットは私が列挙型の配列を編集して、正しくその後のサイズの他のすべてを持つことができます:C#enum(コンパイル時のenumのサイズ)でsentinal値を使用していますか?

typedef enum { 
    errortype1, 
    errortype2, 
    ... 
    errortypeN, 
    ERROR_TYPE_MAX 
} ErrorTypeList; 

int errorcounts[ERROR_TYPE_MAX]; // Create array to hold a counter for each error type 

限り、私は新しいエラーを追加しますERROR_TYPE_MAXの前に型を指定すると、それ以外のところでその値を使用して、列挙型のサイズを指定できます。 C#ので

、しかし、これはそのままでは動作しません:

enum ErrorTypeList { 
    errortype1, 
    errortype2, 
    ... 
    errortypeN, 
    ERROR_TYPE_MAX 
}; 

int errorcounts[ErrorTypeList.ERROR_TYPE_MAX]; // Create array to hold a counter for each error type 

この使用法はnewを使用することを提案しているエラーArray size cannot be specified in a variable declarationを提示します。

実行時(new経由)の配列を私の唯一のオプションとして定義していますか、または列挙型のサイズがコンパイル後に変更されないため、これを新しいものなしに行う方法がありますか?

このタイプのenumサイジングパターンの代わりに、C#に適していますか?

+2

を発生するようそうでない場合、私はおそらく唯一のエントリを追加することになり、私はないと思いますあなたが望む代わりに、フレームワーク設計[ガイドライン推奨](http://msdn.microsoft.com/en-us/library/ms229058.aspx)に、センチネル値を列挙に含めないようにしてください。 –

+0

@ConradFrix優れたリンクと検索、ありがとう。 –

+0

あなたがそれを気に入ってうれしいです。アノテーションが素晴らしいので、[書籍版](http://www.amazon.com/Framework-Design-Guidelines-Conventions-Libraries/dp/0321545613/ref=dp_ob_title_bk)もお勧めします。 –

答えて

5

newを使用する必要があります。

変数/フィールド宣言で配列のサイズが指定されていません。これは、配列インスタンスを作成するときにのみ有効です。

配列の次元数は指定できますが、各次元のサイズは指定できません。配列内のカウンターとトリックだけ動作することを

enum ErrorTypeList { 
    errortype1, 
    errortype2, 
    ... 
    errortypeN // ERROR_TYPE_MAX is not necessary 
}; 


int errorCounts[] = new int[Enum.GetNames(typeof(ErrorTypeList)).Length]; 

注:

+1

彼は新しいものを使う必要はありません。 stackallocはどうですか? http://msdn.microsoft.com/en-us/library/cx9s2sy4.aspx – Kakira

2

固定長配列はunsafe structでのみ定義できます。それ以外の場合、C#は実行時にnewを使用して配列を作成することのみをサポートします。

配列は参照型であり、ヒープに格納されるため、パフォーマンスの違いはありません。

+0

用語ニックピック:配列のコンテキストで "動的"は、通常、サイズは実行時に計算されます。 – delnan

2

あなたの質問の後半部分に答えるために、あなたはこのように、Enumクラスを使用して、enumのエントリ数を取得することができますenumの値が連続している場合これは、Dictionary<ErrorTypeList,int>よりやや壊れやすく、列挙定数に連続しない値または負の値を割り当てることにしても機能します。もちろん、実行時に「要素はありません」という例外を避けるために、カウントをゼロに初期化する必要があります。

5

あなたが列挙型のサイズをしたい場合は、あなたがこれを行うことができます:

enum Foo { A , B , C , ... , } 
... 
int[] someArray = new int[ sizeof(Foo) ] ; 

をしかしsizeofはオクテット内のオブジェクトのサイズを返しますので、それは、あなたが望む何を与えることはありません(4この例では、enumはデフォルトでInt32をラップしているためです)。

このような何か、値で列挙型の数を取得するには:あなたは配列のインデックスに列挙型の値を使用して計画している場合は、あなたがすべき

enum Foo { A , B , C , ... , } 
... 
int[] someArray = new int[ Enum.GetValues(typeof(Foo)).Length ] ; 

をこれは、enumの値が0から1だけインクリメントされることを前提としていることに注意してください。前提条件に違反するenumの定義へのその後の変更は、物事を壊すでしょう。

さらに、列挙型に[Flags]属性が適用されている場合、列挙型のドメインは、定義された離散値の数よりも潜在的にはるかに大きくなります。

あなたは、このように、辞書を使用するようにしたほうが良いでしょう:

[Flags] 
enum Foo { Unknown = 0 , A = 1 , B = 2 , C = 4 , D = 8 , E = 16 , ... , } 
... 
Dictionary<Foo,SomeType> myDictionary = new Dictionary<Foo,SomeType>() ; 

今、あなたのコードはより柔軟です:あなたは、列挙型の内部に配置されているかを気にしないでください。

予想されるキーのセットを辞書にあらかじめ入力しておくこともできます(予想外の値が渡された場合は例外がスローされます)。あなたにもこのような何かを行うことができ

注意するように編集

void DoSomething() 
{ 
    int[] someArray = CreateArrayBasedOnFoo<int>() ; 
    ... 
    return ; 
} 

public T[] CreateArrayBasedOnFoo<T>() 
{ 
    Foo[] values = (Foo[]) Enum.GetValues(typeof(Foo)) ; 
    int lo  = (int) values.Min() ; 
    int hi  = (int) values.Max() ; 
    int domain = (hi - lo) + 1 ; 
    T[] instance = (T[]) Array.CreateInstance(typeof(T), new int[]{domain} , new int[]{lo}) ; 

    return instance ; 
} 

CreateArrayBasedOnFoo<T>()方法が列挙型に合わせてサイズの配列を手の甲、その下限が最小となるでしょう列挙型の値。たとえば、列挙型に3,5,7の3つの離散値がある場合、戻される配列は5要素になり、下限は3になります。

0

列挙型イニシャライザのために、列挙型のエントリの数を使用する安全でない方法は、C#の列挙型の値の境界チェックを実行します。

Enum.IsDefined()やEnum.ToObject()などの検証メソッドが豊富にあるため、数値を検証し、数値を特定の列挙型のエントリに変換することができます。

列挙型クラスのMSDNのリファレンスを参照してください。

http://msdn.microsoft.com/en-us/library/system.enum.aspx

編集明確に問題文を対処するため...

私は辞書のマッピング列挙値と整数カウンタが良いと思いますあなたのニーズにお応えします。誰かがあなたのenumエントリの1つ以上にイニシャライザを張っている場合、それはまだ動作します。

enum MyEnum {a=32, b, c, d=48, e, f} 

Dictionary<MyEnum, int>ErrorCounts = new Dictionary<MyEnum, int>(); 

とあなたが本当にそれを事前に初期化したい場合:

foreach(MyEnum me in Enum.GetValues(typeof(MyEnum))) 
{ 
    ErrorCounts[me] = 0; 
} 

エラー条件が

private void IncrementErrorCount(MyEnum val) 
{ 
    if(ErrorCounts[val] == null) 
     ErrorCounts[val]=1 
    else 
     ErrorCounts[val]++; 
} 
関連する問題