通常、メモリの問題ではなく、型のセマンティクスのために、構造体とクラスのどちらかを選択します。私の値型の中には、非常に大きなメモリ フットプリントがあり、このデータを常にコピーするには大きすぎる場合があります。ですから、不変の値オブジェクトを常に参照渡しするのは良い考えでしょうか? オブジェクトは不変であるため、参照によってオブジェクトを受け入れるメソッドによって変更することはできません。参照渡しの際に他に問題はありますか?
4 に答える
私の値の型のいくつかは、非常に大きなメモリフットプリントを持っています
これは、実装の観点から、値型であってはならないことを示唆しています。「クラス ライブラリを開発するための設計ガイドライン」から、「クラスと構造体の選択」セクション:
型が次の特性をすべて備えていない限り、構造体を定義しないでください。
- プリミティブ型 (integer、double など) と同様に、単一の値を論理的に表します。
- インスタンス サイズが 16 バイト未満です。
- 不変です。
- 頻繁に箱詰めする必要はありません。
代わりに、不変の参照型を作成する必要があるようです。いずれにせよ、多くの点で値オブジェクトのように「感じる」ことになりますが (文字列を考えてください)、それらを渡す効率について心配する必要はありません。
値型の「不変性」は少し流動的な概念です。使用が安全であることを意味するものではありません。ref
// int is immutable, right?
int x = 5;
Foo(ref x);
Console.WriteLine(x); // Eek, prints 6...
...
void Foo(ref int y)
{
y = 6;
}
値の一部を変更するのではなく、値全体をx
まったく異なる値に置き換えます。
不変性は、参照型に関して考えるのがやや簡単です-それでも、それ自体は変更されないオブジェクトを持つことができますが、可変オブジェクトを参照できます...
もちろん、Jon の答えは正しいです。これに追加します。値の型でメソッドを呼び出すと、値の型は既に参照によって渡されます。例えば:
struct S
{
int x;
public S(int x) { this.x = x; }
public void M() { Console.WriteLine(this.x); }
}
メソッド M() は、論理的には次のものと同じです。
public static void M(ref S _this) { Console.WriteLine(_this.x); }
構造体でインスタンス メソッドを呼び出すときはいつでも、呼び出しのレシーバーであった変数にrefを渡します。
では、レシーバーが変数でない場合はどうなるでしょうか。次に、値がレシーバーとして使用される一時変数にコピーされます。値が大きい場合は、高価なコピーになる可能性があります。
値型は値によってコピーされます。そのため、値型と呼ばれます。可能なすべての高価なコピーを見つけてそれらを排除することに細心の注意を払う予定がない限り、私はフレームワーク設計ガイドラインのアドバイスに従います: 構造体を 16 バイト未満に保ち、値で渡します。
また、Jon が正しいことも強調します。構造体を ref で渡すということは、変数への参照を渡すことを意味し、変数は変更される可能性があります。それが「変数」と呼ばれる理由です。C++ にあるような "const ref" は C# にはありません。値の型自体が「不変」であるように見えても、それを保持する変数が不変であることを意味するわけではありません。この不自然ではあるが教育的な例で、その極端な例を見ることができます。
struct S
{
readonly int x;
public S(int x) { this.x = x; }
public void M(ref S s)
{
Console.WriteLine(this.x);
s = new S(this.x + 1);
Console.WriteLine(this.x);
}
}
M が 2 つの異なる数を書き出すことは可能ですか? 構造体は不変であり、したがって x は変更できないと素朴に考えるでしょう。しかし、sとthisはどちらも変数であり、変数は変化する可能性があります:
S q = new S(1);
q.M(ref q);
this
とs
はどちらも への参照であり、何も変化q
を止めていないため、これは 1, 2 を出力します。読み取り専用ではありません。q
要するに、渡したいデータがたくさんあり、それが不変であるという強力な保証がある場合は、構造体ではなくクラスを使用します。大きな構造体はコピーするのに非常にコストがかかる可能性があることに注意してください。
それで、不変の値オブジェクトを常に参照によって渡すのは良い考えではないかと思いますか?オブジェクトは不変であるため、参照によってオブジェクトを受け入れるメソッドによって変更することはできません。参照で渡すときに他の問題はありますか?
あなたが何を意味するのかは明確ではありません。ref
またはパラメータとして渡すことを意味すると仮定するとout
、メソッドは単に新しいインスタンスを保存場所に割り当てることができます。これにより、呼び出し先の保存場所が呼び出し元から渡された保存場所のエイリアスであるため、呼び出し元に表示される内容が変更されます。
周りのインスタンスをコピーするためにメモリの問題を処理している場合はstruct
、のように不変の参照型を作成することを検討する必要がありますstring
。
実際には悪い考えは、あなたがするすべてがクラスを使用することを指しているときに構造体を使用することだと思います
関連する回答: https://stackoverflow.com/questions/2440029/is-it-a-bad-practice-to-pass-structs-by-reference