也说new
今天看到了Anytao的[你必須知道的.NET] 第五回:深入淺出關鍵字---把new說透。Anytao這一系列文章寫得都非常好,其實甚至正是我一直想寫的。比起各種應用層面上的技巧,我更喜歡研究.NET的底層機制。但是光顧了自己研究了,也沒好好寫東西給大家分享。
《把new說透》這篇文章介紹的內容不錯,但Anytao文字上可能沒有表達得很清晰。C# 2.0中關鍵字new有三種作用——1)作為修飾符覆蓋父類中的virtual成員,2)作為運算符創建對象,3)作為泛型類型中對類型形參的約束。
new的這三種功能其實是完全不相干的,Anders Liu個人感覺作為文章來說,應該完全分開在不同的小節中去介紹。
1 new修飾符
new修飾符用于修飾類型成員(屬性、方法等)。
(懶得畫圖寫代碼了,所以采用純文字描述。大家可以看Anytao的代碼)
當父類中編寫了virtual方法時,子類出現了相同簽名的方法時,必須冠以override或new運算符。
如果使用override運算符,則可以實現“多態”。即:將子類對象轉成父類型后,調用virtual方法,實際上執行的是子類中的方法代碼。
而如果使用new運算符,則不會出現上述情況,將子類對象轉成父類型后,調用virtual方法,實際上執行的是還是父類中的方法代碼。
2 new運算符
new運算符用于創建對象。當使用new運算符創建對象時,會發生下列事情:
- 根據元數據中的類型信息,計算對象所需空間,根據值類型/引用類型的區別,在棧或者堆中開辟適當大小的存儲區域。
- 根據元數據中的類型信息,對類成員空間進行排列。并初始化成員。(*)
- 調用構造器。
- 返回對象引用。
所以,string s = new string("asdf");實際上是首先根據string類型信息在堆上開辟存儲空間,排列其成員,然后調用string(string s)簽名的構造器,最后返回新對象引用,并通過等號賦給變量s。
因此,Anytao提到的int i與int i = new int()的區別也就出來了。
但這里Anytao沒有陳述清楚的是,int i出現的位置——int i即可以出現在類中,成為一個字段(域);也可以出現在方法中,成為一個變量(還有一種是出現在方法參數中,但就其語義,和變量是類似的)。
如果int i是一個字段(域)定義,那么兩者是沒有任何區別的。因為,注意上面第二條帶(*)的部分,當客戶代碼初始化當前類的對象時,會同時初始化這個i,將其值置為0。
如果int i是一個變量定義,那么,int i只是聲明了一個局部變量,此時的i不能直接使用,必須首先賦值(如果未賦值就使用,會得到一個編譯錯誤)。而int i = new int()則對i進行了一個初始化。
3 new約束
在泛型類型定義時,可以使用where指定一些約束,其中一種就是new約束。new 約束要求用作類型實參的類型必須帶有公共無參構造器。如class A<T> where T : new();這里只有帶有公共無參構造器的類型才能用作T。
需要注意兩點,1)如果同時存在其他約束,那么new約束應該是最后一個。2)不能用new(int i)的形式來約束擁有指定簽名的構造器。
好了,希望Anders Liu能給Anytao梳理一下文字。
總結
- 上一篇: 机器学习A-Z~简单线性回归
- 下一篇: 脚本宿主程序