2011-01-08 3 views
3

.NET構造体は値型です。つまり、関数Aが構造体を作成し、構造体を変更しようとする関数Bを呼び出すと、Bは構造体の新しいコピーを取得するため、Aの構造体には適用されません。.NETの構造体はコピーライト時にコピーされますか?

構造体は、CLRの他の値型よりもはるかに大きくなる可能性があります。ある関数が大きな構造体を作成し、別の関数を呼び出して構造体を関数に渡すとします。これは10レベルになりますが、すべての関数は構造体からデータを読み取るだけで、フィールドを変更する必要はありません。各関数呼び出しで実際に構造体の新しいコピーが作成された場合、上記のシナリオでは多くの不要な構造体が割り当てられます。

C言語のユーザーは、構造体自体の代わりにポインタを渡すことでこれを避けることができます。また、内部関数がstructのデータを変更してはならない場合は、constキーワードを使用できます。

しかし、C#にはポインタの代わりに参照があり、 "const ref"のようなものはありません。

私の質問は:関数がフィールドを内部で変更しようとしたときにのみ構造体をコピーするように.NETが最適化されているか、構造体が別の関数に渡されたときに常に新しいコピーが作成される

+0

も参照してください。http://stackoverflow.com/questions/85553/when-should-i-use-a-struct-instead-of-a-class –

答えて

4

上記のシナリオは、「割り当て」という点で、このことについて考える多くの不要な構造体

を割り当てるなります本当に何が起こるかと、かなり思い切った不一致です。構造体の値は、CPUレジスタ、スタックが大きくなるか、渡す引数が多すぎる場合はスタックに渡されます。これは安価で、ランタイムサポートメソッドが呼び出されることはなく、割り当てを「解放」するという概念はありません。

これは、ネイティブのC/C++コードとほぼ同じように動作します。構造体パッシングは常にネイティブ呼び出し規約(__fastcall以外)でスタックを通過するので、x86 JITコンパイラはより良いコードを生成する傾向があります。ポインタも同様にサポートされています.Cの場合と同様に、refキーワードで引数を宣言するだけです。ゼロconstキーワードを除いて、あなたはそれなしで生きなければならないでしょう。

構造体が16バイトを超えると、構造体を渡すコストが大幅に上昇します。スタックにプッシュされなくなり、ジッタはローカルスタックフレーム上の値のコピーにポインタを渡すコードを生成します。実際には、コールサイトと呼び出し先で値が2回コピーされます。 .NET Frameworkのガイドでは、構造体が大きすぎる場合にクラスに切り替えることをお勧めします。しかし、refを渡すことは、コピーを避けるためにも機能し、すべてのメンバーがアクセスするという注意書きは間接的です。 Cのように。

構造体の代わりにクラスを使用することを躊躇しないで、ガベージコレクタは非常に効率的です。

1

あなたは参照によって値型を渡すことができます。

public void SomeMethod(ref SomeValueType someValue) 

しかし、あなたの特定の質問に答えるために、いいえ、私はどのような最適化があるとは思わない、また私は彼らが望ましい見つけるだろう。私はむしろ一貫した行動をとるだろう。大規模な値の型を使用していて、それを無制限に渡しているのであれば、それは間違っています。

0

構造体にフィールドとは対照的にプロパティが含まれている場合は、構造体への読み取り専用インターフェイスを宣言し、その代わりに参照を渡すことができます。

public interface IMyReadOnlyStruct 
{ 
    int A { get; } 
} 

public struct MyStruct: IMyReadOnlyStruct 
{ 
    public int A { get; set; } 
} 

public void MyReadOnlyMethod(ref IMyReadOnlyStruct a) 
{ 
    .... 
} 

これは、周囲のオブジェクトに読み取り専用の参照を渡す方法です。これを行うことができるので、C#ではconstをサポートする必要はありません。インターフェイスを使用すると、const参照を持つことができますが、オブジェクトプロパティの任意の指定されたサブセットだけにアクセスできる参照もできます。

あなたの構造体にフィールドが含まれている場合、これはできません。しかし、その場合は、とにかく構造体を変更します。

0

質問に答えるには、 yes構造体は必要に応じてコピーされます:フィールド/変数への書き込み、またはメソッドへの渡し。これは最適化されておらず、そうである必要はありません。

構造体の場合は、変更不可能でなければなりません。フィールドを変更する別のメソッドの問題は、moot:です。変更するべきではありません。です。

大きすぎる問題。オーバーサイズの場合、構造体であってはなりません。それはクラスでなければなりませんが、それが控えめな価値を表しているならば、クラス形式であっても不変のままにしておきたいかもしれません。

両方の問題へのもう一つの答えは、クラスのプロパティ、ない方法に「REF」それを渡すために、またはフィールドとしてそれをカプセル化することですが、IMOのいずれかのこれらのは、通常、彼らは間違って構造体を使用していることを意味最初の場所。

ここで実際に行う変更は、これが実際にであるかどうかを評価することです。は「値」です。値は決して変化しません。したがって、structsは変更する必要はありません。あなたのタイプについてこれを言うことができないなら、おそらく構造体であってはなりません。

関連する問題