質問
可能な重複:
可変構造が悪である理由
構造体を不変にした方が良いということを含め、ここを含む多くの場所で読みました。
この背後にある理由は何ですか? xnaのような、Microsoftが作成した可変の構造体がたくさんあります。おそらくBCLにはもっとたくさんあります。
このガイドラインに従わないことの長所と短所は何ですか?
解決
構造は値を表す必要があります。値は変更されません。 12という数字は永遠です。
ただし、考慮:
Foo foo = new Foo(); // a mutable struct
foo.Bar = 27;
Foo foo2 = foo;
foo2.Bar = 55;
現在foo.Barとfoo2.Barは異なりますが、これはしばしば予期しないことです。特に、プロパティのようなシナリオでは(残念ながらコンパイラがこれを検出します)。しかし、コレクションなども。どのようにして賢明に変異させるのですか?
可変構造体では、データの損失は非常に簡単です。
他のヒント
大きな欠点は、物事があなたが期待するように振る舞わないことです-特に、可変性が直接値とその中の参照型の混合に由来する場合。
正直に言うと、人々が可変構造を使用したときにニュースグループで出くわした奇妙な問題のすべてを頭の中で思い出せませんが、その理由は確かに存在します。 可変構造体は問題を引き起こします。近づかない。
編集:少し前にこのトピックについて書いたメールを見つけました。少し詳しく説明します:
-
それは哲学的に間違っています:構造体はある種の根本的な価値を表すべきです。これらは基本的に不変です。数値5を変更することはできません。変数の値を5から6に変更できますが、論理的に値自体を変更することはありません。
-
これは実際には問題です。多くの奇妙な状況を作り出します。インターフェイスを介して可変である場合は特に悪いです。その後、ボックス化された値の変更を開始できます。うん多くのニュースグループの投稿を見てきましたが、これは人々が可変構造体を使用しようとして問題に遭遇したためです。たとえば、
List<T>.Enumerator
が構造体であるために失敗する非常に奇妙なLINQの例を見ました。
(パフォーマンスクリティカルな)プロジェクトでは頻繁に可変構造体を使用します。コピーセマンティクスの意味を理解しているため、問題にぶつかることはありません。私が知る限り、人々が不変の構造体を提唱する主な理由は、その意味を理解していない人々がトラブルに巻き込まれないようにするためです。
それはそれほどひどいことではありません-しかし、私たちは今、それが<!> quot;福音の真実<!> quot;になる危険にさらされています。 struct mutable。すべてのものと同様に、ルールには例外があります。
可変の構造体よりも安価に操作できるものはありません。そのため、グラフィックス処理ルーチンのような高性能コードでよく見られます。
残念ながら、可変構造体はオブジェクトやプロパティとうまく連携しません。構造体自体の代わりにstuctのコピーを変更するのは簡単すぎます。したがって、これらはほとんどのコードには適切ではありません。
PS可変構造体をコピーするコストを回避するために、それらは通常、配列に格納されて渡されます。
技術的な理由は、可変構造体が実際には実行していないことを実行できるように表示しているためです。設計時のセマンティクスは参照型と同じであるため、開発者にとって混乱を招きます。このコード:
public void DoSomething(MySomething something)
{
something.Property = 10;
}
MySomething
がstruct
であるかclass
であるかによって、動作がまったく異なります。私には、これは説得力がありますが、最も説得力のある理由ではありません。 DDD の値オブジェクトでは、構造体の処理方法への接続を確認できます。 DDDの値オブジェクトは、.Netの値タイプ(したがって構造体)として最適に表現できます。アイデンティティがないため、変更できません。
住所などの観点からこれを考えてください。 <!> quot; change <!> quot;住所ですが、住所自体は変更されていません。実際、新しいアドレスが割り当てられています。概念的には、これは機能します。実際に住所を変更した場合、ルームメイトも移動する必要があるためです。
構造体は不変であるべきであるというガイドラインに従って、ないの長所と短所を求めました。
短所:短所は既存の回答で十分にカバーされており、説明されているほとんどの問題は同じ原因によるものです-構造体の値のセマンティクスによる予期しない動作。
長所:可変構造体を使用する主な長所は、パフォーマンスです。当然、このアドバイスには最適化に関する通常の注意事項がすべて含まれています。コードの一部を最適化する必要があることを確認し、変更がプロファイリングによって実際にコードのパフォーマンスを最適化することを確認してください。
可変構造を使用するタイミングについて説明している優れた記事については、Rico Marianiの値ベースのプログラミングに関するパフォーマンスクイズ(より具体的には、回答)。
構造体は一般に、ある種の単一の団結を表す必要があります。そのため、値のプロパティの1つを変更するのはあまり意味がありません。何らかの形で異なる値が必要な場合は、まったく新しい値を作成する方が合理的です。
不変の構造体を使用すると、セマンティクスがより簡単になり、次のような落とし穴を回避できます。
// a struct
struct Interval {
int From { get; set; }
int To { get; set; }
}
// create a list of structs
List<Interval> intervals = new List<Interval>();
// add a struct to the list
intervals.Add(new Interval());
// try to set the values of the struct
intervals[0].From = 10;
intervals[0].To = 20;
結果として、リスト内の構造体はまったく変更されません。式Interval [0]は、リストから構造体の値をコピーし、一時値のプロパティを変更しますが、値がリストに戻されることはありません。
編集:配列の代わりにリストを使用するように例を変更しました。
構造体をコピーすると、その内容がコピーされるため、コピーしたバージョンを変更すると、<!> quot; original <!> quot;更新されません。
これはエラーの原因になります。構造体をコピーして(メソッドに渡すだけで)コピーの修正というトラップに陥ったことがわかっている場合でもです。
先週私はちょうど再び起こったので、バグを探すのに1時間かかりました。
不変の構造体を保持すると、それが防止されます...
それ以外の場合、最初に構造体を使用する本当に正当な理由があることを確認する必要があります-<!> quot; optimization <!> quot;または<!> quot;スタックにすばやく割り当てるものが欲しい<!> quot;答えとしてカウントされません。マーシャリングまたはレイアウトに依存するもの-わかりましたが、通常はこれらの構造体を非常に長く保持するべきではありません。それらはオブジェクトではなく値です。
構造体を不変にする必要がある理由は、 ValueTypes 。つまり、メソッドに渡すたびにコピーされます。
たとえば、構造体を返すプロパティがある場合、その構造体のフィールドの値を変更しても価値はありません。ゲッターは構造体のコピーを返すため、構造体への参照よりも。私はこれをコードで見たことがありますが、キャッチするのは難しい場合がよくあります。
不変性のために構造体を設計すると、プログラマがこれらの間違いを避けるのに役立ちます。