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

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

黄舟
黄舟オリジナル
2017-02-11 13:55:571626ブラウズ

コードがコンパイラーによるボックス化の繰り返しを引き起こす場合は、手動ボックス化に変更してコードの実行を高速化できます。次のコードを参照してください:

            //手动装箱
            Int32 v = 5;

            //由于string.Format的参数是object类型,所以这里会造成三次装箱。
            Console.WriteLine(string.Format("{0},{1},{2}", v, v, v));

            //修改一下,当然这只是一个小技巧,比如程序中对同一个值的同一个操作执行多次,
            //应该都是要先执行一次,然后再使用的。
            Object o = v;//装箱一次

            Console.WriteLine(string.Format("{0},{1},{2}", o, o, o));

前のコード セグメントを通して、プログラムを作成するときに判断するのは簡単です。もう一度言いますが、値の型をボックス化する必要があるのはどのような場合ですか?値の型への参照を取得したい場合、これはボックス化にすぎません。値型と参照型の違いは、ここでも明確にわかります。
1. 値型はマネージド ヒープに領域を割り当てませんが、参照型はインスタンス化後にヒープ上のクラスで指定されたメンバーに領域を割り当てます。
2. 値型には、ヒープ上にオブジェクトの追加メンバー、つまり「型オブジェクト ポインター」と「同期インデックス」がありません。
ボックス化されていない値型には同期されたインデックスがないため、その型が配置されているクラスのメソッド (ロックなど) を使用して、複数のスレッドがこのインスタンスへのアクセスを同期できるようにすることはできません。
ボックス化されていない値型には型オブジェクト ポインターがありませんが、Equals、GetHashCode、ToString など、型によって継承またはオーバーライドされた仮想メソッドを引き続き呼び出すことができます。値の型がこれらの仮想メソッドのいずれかをオーバーライドする場合、値の型は暗黙的にシールされており、そこから型を派生できないため、CLR はそのメソッドを非仮想的に呼び出すことができます。さらに、仮想メソッドの呼び出しに使用される値型インスタンスはボックス化されません。オーバーライドされた仮想メソッドが基本クラスのメソッドの実装を呼び出す場合、基本クラスの実装が呼び出されたときに、値型インスタンスはボックス化されます。これらのメソッドは System.Object によって定義されているため、この引数がヒープ上のオブジェクトへのポインターであることを想定しています。
さらに、値型のボックス化されていないインスタンスをその型のインターフェイスの 1 つにキャストするには、インスタンスをボックス化する必要があります。インターフェイス変数にはヒープ上のオブジェクトへの参照が含まれている必要があるためです。以下のコードを見てください:

 class Program
    {
        static void Main(string[] args)
        {
            Point p1 = new Point(10, 10);

            Point p2 = new Point(20, 20);

            //调用ToString不装箱,这里ToString是一个虚方法
            Console.WriteLine(p1.ToString());

            //GetType是一个非虚方法,p1要装箱
            Console.WriteLine(p1.GetType());

            //这里调用的是public int CompareTo(Point p)
            //p2不会装箱
            Console.WriteLine(p1.CompareTo(p2));

            //p1要装箱,这就是将未装箱的值类型转为类型的某个接口时
            IComparable c = p1;

            Console.WriteLine(c.GetType());

            //这里调用的是public Int32 CompareTo(Object o),
            //而且c本来就是一个引用,因此不装箱了
            Console.WriteLine(p1.CompareTo(c));

            //这里调用的是c的CompareTo方法,参数是object型的
            //所以要对p2装箱
            Console.WriteLine(c.CompareTo(p2));

            //对c拆箱,并复制值到p2中
            p2 = (Point)c;

            Console.WriteLine(p2.ToString());
        }
    }
    
     internal struct Point : IComparable
    {
        private Int32 x;

        private Int32 y;

        public Point(Int32 x, Int32 y)
        {
            this.x = x;

            this.y = y;
        }

        public override string ToString()
        {
            return string.Format("{0},{1}", x, y);//这里装箱两次,不知道有没好办法。
        }

        public int CompareTo(Point p)
        {
            return Math.Sign(Math.Sqrt(x * x + y * y) - Math.Sqrt(p.x * p.x + p.y * p.y));
        }

        public Int32 CompareTo(Object o)
        {
            if (GetType() != o.GetType())
            {
                throw new ArgumentException("o is not Point.");
            }

            return CompareTo((Point)o);
        }
    }

上記は、C# の基礎知識の内容です 基礎知識 (19) 値型のボックス化とアンボックス化 (2) 関連する内容については、PHP 中国語 Web サイト ( www.php.cn)!


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