首頁  >  文章  >  後端開發  >  C#基礎知識整理 基礎知識(19) 值類型的裝箱與拆箱(二)

C#基礎知識整理 基礎知識(19) 值類型的裝箱與拆箱(二)

黄舟
黄舟原創
2017-02-11 13:55:571606瀏覽

如果程式碼中會造成編譯器的反覆裝箱,可改為手動裝箱,這樣來使程式碼執行更快,看下面程式碼:

            //手动装箱
            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、值類型沒有堆疊上的物件的額外成員,即「類型物件指標」、「同步索引」。
未裝箱的值類型沒有同步索引,因此不能使用該類型所在類別的方法(例如lock)讓多個執行緒同步對這個實例的存取。
雖然未裝箱的值型別沒有型別物件指針,但仍可呼叫由型別繼承或重寫的虛方法,例如Equals,GetHashCode,ToString。如果值類型重寫了其中任何一個虛擬方法,那麼CLR可以非虛地呼叫該方法,因為值類型是隱式密封的,沒有任何類型能夠從它派生。此外,用於呼叫虛擬方法的值類型實例不會被裝箱。如果重寫的虛擬方法要呼叫方法在基底類別中的實現,那麼在呼叫基底類別的實作時,值類型實例會裝箱。因為這些方法是有System.Object定義的,所以這些方法期望this實參是指向堆上的一個物件的指標。
此外,將值類型的一個未裝箱實例轉換為類型的某個介面是,要求實例進行裝箱。因為介面變數必須包含對堆上的一個物件的參考。看下面程式碼:
 

 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) 值類型的裝箱和拆箱(二)的內容,更多相關內容請關注PHP中文網(www.php.cn)!

 

陳述:
本文內容由網友自願投稿,版權歸原作者所有。本站不承擔相應的法律責任。如發現涉嫌抄襲或侵權的內容,請聯絡admin@php.cn