10

値型のインスタンスを参照型のインスタンスとして扱う必要がある場合があります。このような状況では、値型インスタンスは、ボクシングと呼ばれるプロセスを通じて参照型インスタンスに変換できます。値型のインスタンスがボックス化されると、記憶域がヒープに割り当てられ、インスタンスの値がその領域にコピーされます。このストレージへの参照がスタックに置かれます。ボックス化された値はオブジェクトであり、値型インスタンスの内容を含む参照型です。

.NET の共通型システムを理解する

ウィキペディアにはJava の例があります。しかし、C# では、値の型をボックス化する必要があるのはどのような場合でしょうか? または、より良い/同様の質問は、スタックではなくヒープ (ボックス化) に値の型を格納したいのはなぜですか?

4

9 に答える 9

14

通常、値の型をボックス化することは避けたいと思うでしょう。

ただし、これが役立つ場合がまれにあります。たとえば、1.1 フレームワークをターゲットにする必要がある場合、ジェネリック コレクションにはアクセスできません。.NET 1.1 でコレクションを使用するには、値の型を System.Object として扱う必要があり、これによりボックス化/ボックス化解除が発生します。

これが .NET 2.0+ で役立つケースがまだあります。値型を含むすべての型を直接オブジェクトとして扱うことができるという事実を利用したい場合はいつでも、ボックス化/ボックス化解除を使用する必要がある場合があります。これは、(ジェネリック コレクションで T の代わりに object を使用することにより) コレクションに任意の型を保存できるため、便利な場合がありますが、一般的には、型の安全性が失われるため、これを回避することをお勧めします。ただし、ボックス化が頻繁に発生する 1 つのケースは、リフレクションを使用している場合です。リフレクションでの呼び出しの多くは、型が事前にわからないため、値の型を操作するときにボックス化/ボックス化解除が必要になります。

于 2009-06-22T17:45:07.507 に答える
13

値型を意図的にボックス化する正当な理由はほとんどありません。ほとんどの場合、値の型をボックス化する理由は、型を認識しないコレクションに格納するためです。たとえば、古いArrayListは、参照型であるオブジェクトのコレクションです。整数などを収集する唯一の方法は、それらをオブジェクトとしてボックス化し、ArrayList に渡すことです。

最近ではジェネリック コレクションがあるため、これはあまり問題になりません。

于 2009-06-22T17:43:54.407 に答える
9

ボクシングは通常、必要なときに.NETで自動的に行われます。多くの場合、参照型を期待するものに値型を渡すとき。一般的な例はstring.Format()です。このメソッドにプリミティブ値型を渡すと、呼び出しの一部としてボックス化されます。それで:

int x = 10;
string s = string.Format( "The value of x is {0}", x ); // x is boxed here

これは、値型(x)が自動的にボックス化されて、オブジェクトを予期するメソッドに渡される単純なシナリオを示しています。一般に、可能な場合はボクシングの値型を避けたいと思いますが、場合によっては非常に便利です。

興味深いことに、.NETでジェネリックスを使用する場合、パラメーターまたは型のメンバーとして使用するときに値型はボックス化されません。これにより、ジェネリックスは、すべてを{object}として扱い、型に依存しない古いC#コード(ArrayListなど)よりも効率的になります。List<T>これにより、またはDictionary<T,K>以上ArrayListまたはのようなジェネリックコレクションを使用するもう1つの理由が追加されますHashtable

于 2009-06-22T17:53:23.627 に答える
5

Eric Lippert の 2 つの素晴らしい記事をお勧めします。

http://blogs.msdn.com/ericlippert/archive/2009/04/27/the-stack-is-an-implementation-detail.aspx

http://blogs.msdn.com/ericlippert/archive/2009/05/04/the-stack-is-an-implementation-detail-part-two.aspx

これは私が100%同意する引用です

値型のローカルにスタックを使用することは、CLR がユーザーに代わって実行する最適化にすぎません。値型の関連する機能は、値によってコピーされるセマンティクスを持っていることであり、ランタイムによって解放が最適化される場合があることではありません。

99% のアプリケーション開発者は、値型がヒープではなくスタックにある理由や、ここで得られるパフォーマンスの向上について気にする必要はありません。Juts は非常に単純なルールを念頭に置いています。

  1. 必要のない場合はボックス化/ボックス化解除を避け、ジェネリック コレクションを使用します。ほとんどの問題は、独自の型を定義した場合ではなく、既存の型を不適切に使用した場合 (Microsoft または同僚によって定義されたもの) に発生します。
  2. 値の型を単純にします。10 ~ 20 個のフィールドを持つ構造体が必要な場合は、クラスを作成したほうがよいと思います。ときどき関数に値を渡すたびに、そのすべてのフィールドがコピーされると想像してみてください...
  3. 内部に参照型フィールドを持つ値型を持つことはあまり有用ではないと思います。String および object フィールドを持つ struct と同様です。
  4. 格納場所ではなく、必要な機能に応じて必要なタイプを定義します。構造体はクラスに比べて機能が制限されているため、構造体がデフォルト コンストラクターのように必要な機能を提供できない場合は、クラスを定義します。
  5. 他の型のデータに対して何らかのアクションを実行できるものは、通常、クラスとして定義されます。異なる型の構造体操作は、ある型を別の型にキャストできる場合にのみ定義する必要があります。int を double にキャストできるため、int を double に追加できるとします。
  6. 何かがステートレスでなければならない場合、それはクラスです。
  7. ためらっている場合は、参照型を使用してください。:-)

特殊なケースではどのルールでも除外を許可しますが、過度に最適化しようとしないでください。

ps 私は、スタックとヒープの違いを知らない 2 ~ 3 年の経験を持つ ASP.NET 開発者に会いました。:-( 私がインタビュアーなら、そのような人を雇うことはありません。

于 2009-06-22T18:49:54.173 に答える
2

C# でのボクシングの良い例は、 ArrayListのような非ジェネリック コレクションで発生すると思います。

于 2009-06-22T17:44:39.413 に答える
1

1 つの例は、メソッドがオブジェクト パラメーターを受け取り、値の型を渡す必要がある場合です。

于 2009-06-22T17:45:44.077 に答える
1

以下は、ボックス化/ボックス化解除の例です

ArrayList ints = new ArrayList();
myInts.Add(1); // boxing
myInts.Add(2); // boxing

int myInt = (int)ints [0]; // unboxing

Console.Write("Value is {0}", myInt); // boxing
于 2009-06-22T17:46:35.383 に答える
1

これが発生する状況の 1 つは、たとえば、オブジェクト型のパラメーターを期待するメソッドがあり、プリミティブ型の 1 つ (int など) を渡す場合です。または、パラメーターを int 型の 'ref' として定義した場合。

于 2009-06-22T17:47:08.973 に答える
1

コード

int x = 42;
Console.Writeline("The value of x is {0}", x );

内部でキャストをWriteline行うため、実際にはボックス化およびボックス化解除します。intこれを回避するには、次のことができます

int x = 42;
Console.Writeline("The value of x is {0}", x.ToString());

微妙なバグに注意!

独自の型を として宣言することで、独自の値型を宣言できますstruct。多くのプロパティを持つを宣言し、structいくつかのインスタンスを の中に入れたとしますArrayList。もちろん、これはそれらをボックス化します。演算子を介して参照[]し、型にキャストしてプロパティを設定します。copyにプロパティを設定するだけです。ArrayListにあるものはまだ変更されていません。

このため、値の型は常に不変である必要があります。つまり、すべてのメンバー変数を作成readonlyして、コンストラクターでのみ設定でき、変更可能な型をメンバーとして持たないようにします。

于 2009-06-22T19:21:45.053 に答える