ホームページ バックエンド開発 C#.Net チュートリアル C#基礎知識編 基礎知識(18) 値型のボックス化とアンボックス化(1)

C#基礎知識編 基礎知識(18) 値型のボックス化とアンボックス化(1)

Feb 11, 2017 pm 01:49 PM

ボックス化とボックス化解除について詳しく知ることは、実際には非常に興味深いことです。まず、ボックス化とボックス化解除がなぜ起こるのか見てみましょう。
次のコードを見てください:

    class Program
    {
        static void Main(string[] args)
        {
            ArrayList array = new ArrayList();

            Point p;//分配一个

            for (int i = 0; i < 5; i++)
            {
                p.x = i;//初始化值

                p.y = i;

                array.Add(p);//装箱
            }
        }
    }

    public struct Point
    {
        public Int32 x;

        public Int32 y;
    }
ログイン後にコピー

5 回ループし、毎回 Point 値タイプのフィールドを初期化し、それを ArrayList に入れます。 Structは値型の構造体ですが、ArrayListには何が格納されるのでしょうか? ArrayList の Add メソッドをもう一度見てみましょう。 MSDN で Add メソッドを参照できます:
public virtual int Add(Object value),
Add のパラメータが Object 型であることがわかります。つまり、必要なパラメータはオブジェクトへの参照です。つまり、ここでのパラメータは参照型である必要があります。参照型とは何かについては、詳しく説明する必要はありません。それはヒープ上のオブジェクトへの参照にすぎません。ただし、理解を容易にするために、ヒープとスタックについてもう一度話しましょう。
1. スタック領域 (スタック) - コンパイラーによって自動的に割り当ておよび解放され、関数のパラメーター値、ローカル変数値などが格納されます。
2. ヒープ領域(ヒープ) - プログラマによって割り当てられ、解放されます。プログラマが解放しない場合、プログラムの終了時に OS によって再利用される可能性があります。
例:

    class Program
    {
        static void Main(string[] args)
        {
            Int32 n;//这是值类型,存放在栈中,Int32初始值为0
            
            A a;//此时在栈中开辟了空间

            a = new A();//真正实例化后的一个对象则保存在堆中。
        }
    }

    public class A
    {
        public A() { }
    }
ログイン後にコピー

上記の質問に戻りますが、Add メソッドには参照型のパラメーターが必要です。どうすればよいでしょうか?次に、ボックス化を使用する必要があります。いわゆるボックス化とは、値型を参照型に変換することです。変換プロセスは次のとおりです:
1. マネージド ヒープにメモリを割り当てます。割り当てられるメモリ量は、値型の個々のフィールドで必要なメモリ量に、マネージド ヒープ内のすべてのオブジェクトが持つ 2 つの追加メンバー (型オブジェクト ポインターと同期ブロック インデックス) で必要なメモリ量を加えたものです。
2. 値の型フィールドを新しく割り当てられたメモリにコピーします。
3. オブジェクトのアドレスを返します。この時点で、アドレスはオブジェクトへの参照であり、値の型は参照型に変換されています。
このようにして、Add メソッドで、ボックス化された Point オブジェクトへの参照が保存されます。ボックス化されたオブジェクトは、プログラマが処理するか、システムのガベージ コレクションがそれを処理するまで、ヒープ内に残ります。この時点で、ボックス化された値型の有効期間は、ボックス化されていない値型の有効期間を超えます。
上記のボックス化では、配列の 0 番目の要素を取り出したい場合は、当然ボックス化を解除する必要があります。
Point p = (Point)array[0]; ここで行う必要があるのは、参照を取得することです。 ArrayList の要素 0 にそれを Point 値型 p に入れます。この目標を達成するには、どのように実装すればよいでしょうか。まず、ボックス化された Point オブジェクトの各 Point フィールドのアドレスを取得します。開梱はこれで終わりです。これらのフィールドに含まれる値は、ヒープからスタックベースの値型インスタンスにコピーされます。アンボックス化は本質的に、オブジェクトに含まれるプリミティブ値型への参照を取得するプロセスです。実際、参照はボックス化されたインスタンスのボックス化されていない部分を指します。したがって、ボックス化とは異なり、ボックス化解除ではメモリ内のバイトをコピーする必要がありません。ただし、もう 1 つの点があります。ボックス化解除直後にフィールド コピー操作が発生します。
したがって、ボックス化とボックス化解除はプログラムの速度とメモリ消費量に悪影響を与えるため、プログラムがボックス化/ボックス化解除操作を自動的に実行するタイミングに注意し、コードを記述するときにこのような状況を避けるようにしてください。
ボックス化を解除するときは、次の例外に注意してください。
1. 「ボックス化された値型インスタンスへの参照」を含む変数が null の場合、NullReferenceException がスローされます。
2. 参照が指すオブジェクトが期待される値型のボックス化されたインスタンスではない場合、InvalidCastException がスローされます。
たとえば、次のコード スニペット:

             Int32 x = 5;

            Object o = x;

            Int16 r = (Int16)o;//抛出InvalidCastException异常
ログイン後にコピー

これは、ボックス化を解除するときにのみ元のボックス化されていない値の型に変換できるためです。上記のコードを次のように変更します:

             Int32 x = 5;

            Object o = x;

            //Int16 r = (Int16)o;//抛出InvalidCastException异常

            Int16 r = (Int16)(Int32)o;
ログイン後にコピー

現時点では正しいです。

ボックス化解除後、次のコードに示すように、フィールドのコピーが行われます:

            //会发生字段复制
            Point p1;

            p1.x = 1;

            p1.y = 2;

            Object o = p1;//装箱,发生复制

            p1 = (Point)o;//拆箱,并将字段从已装箱的实例复制到栈中
ログイン後にコピー

次のコードセグメントを見てください:

            //要改变已装箱的值

            Point p2;

            p2.x = 10;

            p2.y = 20;

            Object o = p2;//装箱

            p2 = (Point)o;//拆箱

            p2.x = 40;//改变栈中变量的值

            o = p2;//再一次装箱,o引用新的已装箱实例
ログイン後にコピー

ここでの目的は、ボックス化後の p2 の x 値を 40 に変更することです。まず、ボックス化解除が 1 回実行され、フィールドのコピーがスタックに実行され、フィールドの値がスタック上で変更され、次にボックス化が実行されます。その時点で、新しいボックス化されたインスタンスがヒープ上に作成されます。 。このことから、ボックス化/ボックス化解除およびコピーがプログラムのパフォーマンスに与える影響もわかります。

さらにいくつかのボックス化とボックス化解除のコード スニペットを見てみましょう:

            //装箱拆箱演示
            Int32 v = 5;

            Object o = v;

            v = 123;

            Console.WriteLine(v + "," + (Int32)o);
ログイン後にコピー

ここでは 3 つのボックス化が発生していますが、Console.WriteLine でさらに 1 つのボックス化が発生していることがはっきりとわかります。ここの WriteLine には文字列型パラメータがあり、文字列が参照型であることは誰もが知っているため、ここでは (Int32)o をボックス化する必要があります。ここでも、プログラム内で文字列を接続するために + 記号を使用する問題について説明します。接続中に複数の値の型がある場合、いくつかのボックス化操作が実行されます。

ただし、上記のコードは変更できます:

            Object o = v;

            v = 123;
ログイン後にコピー

この方法では、ボックス化は行われません。
次のコードをもう一度見てください:

            //修改后
            Console.WriteLine(v.ToString() + "," + o);
ログイン後にコピー

ここでは 1 つのボックス化、つまり Object o = v のみが発生します。ただし、Console.WriteLine は int、bool、double などでオーバーロードされているため、ここではボックス化は発生しません。

上記はC#の基礎知識の内容です 基礎知識(18) 値型のボックス化とアンボックス化(1) その他の関連内容については、PHP中国語Webサイト(www.php.cn)に注目してください。

このウェブサイトの声明
この記事の内容はネチズンが自主的に寄稿したものであり、著作権は原著者に帰属します。このサイトは、それに相当する法的責任を負いません。盗作または侵害の疑いのあるコンテンツを見つけた場合は、admin@php.cn までご連絡ください。

ホットAIツール

Undresser.AI Undress

Undresser.AI Undress

リアルなヌード写真を作成する AI 搭載アプリ

AI Clothes Remover

AI Clothes Remover

写真から衣服を削除するオンライン AI ツール。

Undress AI Tool

Undress AI Tool

脱衣画像を無料で

Clothoff.io

Clothoff.io

AI衣類リムーバー

AI Hentai Generator

AI Hentai Generator

AIヘンタイを無料で生成します。

ホットツール

メモ帳++7.3.1

メモ帳++7.3.1

使いやすく無料のコードエディター

SublimeText3 中国語版

SublimeText3 中国語版

中国語版、とても使いやすい

ゼンドスタジオ 13.0.1

ゼンドスタジオ 13.0.1

強力な PHP 統合開発環境

ドリームウィーバー CS6

ドリームウィーバー CS6

ビジュアル Web 開発ツール

SublimeText3 Mac版

SublimeText3 Mac版

神レベルのコード編集ソフト(SublimeText3)

C# を使用した Active Directory C# を使用した Active Directory Sep 03, 2024 pm 03:33 PM

C# を使用した Active Directory のガイド。ここでは、Active Directory の概要と、C# での動作方法について、構文と例とともに説明します。

C# シリアル化 C# シリアル化 Sep 03, 2024 pm 03:30 PM

C# シリアル化のガイド。ここでは、C# シリアル化オブジェクトの導入、手順、作業、例についてそれぞれ説明します。

C# の乱数ジェネレーター C# の乱数ジェネレーター Sep 03, 2024 pm 03:34 PM

C# の乱数ジェネレーターのガイド。ここでは、乱数ジェネレーターの仕組み、擬似乱数の概念、安全な数値について説明します。

C# データ グリッド ビュー C# データ グリッド ビュー Sep 03, 2024 pm 03:32 PM

C# データ グリッド ビューのガイド。ここでは、SQL データベースまたは Excel ファイルからデータ グリッド ビューをロードおよびエクスポートする方法の例について説明します。

C# のパターン C# のパターン Sep 03, 2024 pm 03:33 PM

C# のパターンのガイド。ここでは、C# のパターンの概要と上位 3 種類について、その例とコード実装とともに説明します。

C# の素数 C# の素数 Sep 03, 2024 pm 03:35 PM

C# の素数ガイド。ここでは、C# における素数の導入と例を、コードの実装とともに説明します。

C# の階乗 C# の階乗 Sep 03, 2024 pm 03:34 PM

C# の Factorial のガイド。ここでは、C# での階乗の概要について、さまざまな例とコード実装とともに説明します。

マルチスレッドと非同期C#の違い マルチスレッドと非同期C#の違い Apr 03, 2025 pm 02:57 PM

マルチスレッドと非同期の違いは、マルチスレッドが複数のスレッドを同時に実行し、現在のスレッドをブロックせずに非同期に操作を実行することです。マルチスレッドは計算集約型タスクに使用されますが、非同期はユーザーインタラクションに使用されます。マルチスレッドの利点は、コンピューティングのパフォーマンスを改善することですが、非同期の利点はUIスレッドをブロックしないことです。マルチスレッドまたは非同期を選択することは、タスクの性質に依存します。計算集約型タスクマルチスレッド、外部リソースと相互作用し、UIの応答性を非同期に使用する必要があるタスクを使用します。

See all articles