2011-11-16 12 views
12

私は二つのリストが含まれていstructコンストラクタを使用せずに構造体のメンバーを初期化する方法はありますか?

struct MonthData 
{ 
    public List<DataRow> Frontline; 
    public List<DataRow> Leadership; 
} 

はしかし、私は、構造体が作成されたときの両方を初期化したいです。私がしようとした場合:

struct MonthData 
{ 
    public List<DataRow> Frontline = new List<DataRow>(); 
    public List<DataRow> Leadership = new List<DataRow>(); 
} 

それから私は得る:

Error 23 'MonthData.Frontline': cannot have instance field initializers in structs 
... 

構造体は、パラメータなしのコンストラクタを持つことができないので、私はどちらかのコンストラクタでこれを設定することはできません。これまでのところ、私は、次のオプションを見ることができます:

  1. 私は
  2. MonthData
  3. のインスタンスを作成するときに、パラメータを持つコンストラクタを作成し、ことを使用する代わりに、構造体
  4. のクラスを使用して、両方のプロパティを初期化します
  5. 初期化するプロパティのgetterとsetterを作成してください。 lazily。

これにはどのような方法が推奨されますか?今、私はこれをクラスをベストアイデアにすると考えています。

+0

これをクラスにします。構造体に参照型を追加すると、それはもはや値型ではなくなります。 – drdwilcox

+1

参照型(クラス)と値型(構造体)を作ることは本当に問題ありませんか?もしそうなら、それをクラスにしてください。 – BoltClock

+0

ええ、この型が構造体であることは意味がありません。 –

答えて

7

代わりにクラスを使用する必要があります。 MSDN

通常、クラスは、より複雑な動作や、クラスオブジェクトの作成後に変更するデータをモデル化するために使用されます。構造体は、主に構造体の作成後に変更する予定のないデータを含む小さなデータ構造に最適です。

1

コンストラクタでこれを行う方法はありません。 CLRでは、構造体のインスタンスを作成することができます。単純にメモリを初期化し、ctorのオーバーヘッドを回避します。ただし、この知識を活用して、同じ観察可能な効果を持つ遅延初期化プロパティを作成することができます。例えば

:あなただけの構文について尋ねている場合は

struct MonthData { 
    private bool m_initialized; 
    private List<DataRow> m_frontLine; 
    private List<DataRow> m_leaderShip; 

    public List<DataRow> FrontLine { 
    get { 
     EnsureInitialized(); 
     return m_frontLine; 
    } 
    } 

    public List<DataRow> LeaderShip { 
    get { 
     EnsureInitialized(); 
     return m_leaderShip; 
    } 
    } 

    void EnsureInitialized() { 
    if (!m_initialized) { 
     m_initialized = true; 
     m_frontLine = new List<DataRow>(); 
     m_leaderShip = new List<DataRow>(); 
    } 
    } 
} 
+0

そうですね、このようなやり方は私の第二の選択だろうと思います。しかし、このような単純なオブジェクトでは、私はここで他の人に同意する傾向があり、これはちょうどクラスであるべきだと思う - 特に2つの参照型が含まれているからです。 –

+1

@MikeChristensen一般的にはい、それはおそらくクラスであるべきです。私の答えは、「コーナーに詰まり、構造体を使用してからこれを行う必要がある場合」です。 – JaredPar

+0

そうですが、工場のアプローチと怠惰な初期化アプローチはかなりクールだと思います。 。 –

6

...代わりに静的な工場を建設し、使用してみてください...一般的には、構造体は不変であるもののために使用すべきである、と(パブリックコンストラクタを呼び出す)ファクトリは、パブリックコンストラクタを使用するよりも、不変型に対して優れたアプローチです。

struct MonthData 
    {  
     public List<DataRow> Frontline; 
     public List<DataRow> Leadership; 
     private MonthData(List<DataRow> frontLine = null, 
         List<DataRow> leadership = null) 
     { 
     Frontline = frontLine?? new List<DataRow>(); 
     Leadership = leadership?? new List<DataRow>(); 
     } 
     public static MonthData Factory(
      List<DataRow> frontLine= null, 
      List<DataRow> leadership= null) 
     { return new MonthData(frontLine, leadership); } 
    } 
+0

これは間違いなく面白いアプローチです。前述したように、私のオブジェクトは不変ではありません。その人の人生)だからおそらくクラスが一番です。しかし、アイデアのために+1 –

+0

私は静的なファクトリメソッドの考え方が好きです。構造体にインスタンスフィールドイニシャライザがありません。したがって、 'public list FrontLine = new List ()'はコンパイルされません。 –

+0

@Jim Mis、yes、編集せずにカットアンドペースト... –

6

あなたは私にはどんな意味がありません、とにかくあなたの構造体に値型として構造体のための使用を参照型(List<T>)を使用しています。私はちょうどクラスに行くだろう。

+0

もう1つの方法は、 'ImmutableArray 'を使用し、@CharlesBretanaに記載されているビルダーメソッドを使うことです。 – m93a

1

CLRが、構造体型のものが、そのようなコードの外側に何か目に見えるようになる前に、いくつかの初期化コードを実行できることを保証する手段を許可していればいいでしょう。構造体型の配列を作成するときでも、配列自体への参照がどこにでも公開される前に、CLRが配列の個々の要素をすべて参照によって渡すようにすることで可能でした。残念なことに、配列の作成中に例外がスローされた場合、状況が厄介になりました。コンストラクタに副作用がない場合、問題はありません。単に配列を破棄して、正常に作成されたオブジェクトが存在しなかったと思わせます。しかし、副作用を持つコンストラクタはいくつかの問題を引き起こす可能性があります。

しかし、構築時に構造を初​​期化する方法がないため、初期化を必要とするオブジェクトで値型のセマンティクスを実現するうえでうまくいきません。ごめんなさい。たとえ値型セマンティクスがあなたの型にとってより適切であったとしても(あるものよりはるかに頻繁に信じられるように)、初期化が必要な場合には参照型を使用する必要があります。 structの遅延初期化は実際には機能しません。たとえば、辞書<文字列、MonthData >という名前のMyDictがある場合は、MyDict( "George")へのアクセスを繰り返します.FrontLineはそれぞれ新しいListを生成します。不快な。

変更可能な構造体は悪ではありません。私は、もしあれば、彼らの強力な主張者の一人です。それにもかかわらず、.netのmutable構造体の扱いにはいくつかの制限があり、value型のセマンティクスが適切な多くの状況が存在しますが、.netの制限はそのようなセマンティクスを適切に提供することを不可能にします。

関連する問題