[你必须知道的.NET] 第五回:深入浅出关键字---把new说透
?本文將介紹以下內容:
- 面向對象基本概念
- new關鍵字深入淺出
- 對象創建的內存管理?
1.?引言
園子里好像沒有或者很少把new關鍵字拿出來說的,那我就占個先機吧,呵呵。那么,我們到底有必要將一個關鍵字拿出來長篇大論嗎?看來是個問題。回答的關鍵是:你真的理解了new嗎?如果是,那請不要浪費時間,如果不是,那請繼續本文的循序之旅。
下面幾個 問題可以大概的考察你對new的掌握,開篇之前,希望大家做個檢驗,如果通過了,直接關掉本頁即可。如果沒有通過,希望本文的闡述能幫你找出答案。
2. 基本概念
一般說來,new關鍵字在.NET中用于以下幾個場合,這是MSDN的典型解釋:
- 作為運算符, 用于創建對象和調用構造函數。
本文的重點內容,本文在下一節來重點考慮。
- 作為修飾符,用于向基類成員隱藏繼承成員。
作為修飾符,基本的規則可以總結為:實現派生類中隱藏方法,則基類方法必須定義為virtual;new作為修飾符,實現隱藏基類成員時,不可和override共存,原因是這兩者語義相斥:new用于實現創建一個新成員,同時隱藏基類的同名成員;而override用于實現對基類成員的擴展。
另外,如果在子類中隱藏了基類的數據成員,那么對基類原數據成員的訪問,可以通過base修飾符來完成。
例如:?
new作為修飾符- 作為約束,用于在泛型聲明中約束可能用作類型參數的參數的類型。
MSDN中的定義是:new?約束指定泛型類聲明中的任何類型參數都必須有公共的無參數構造函數。當泛型類創建類型的新實例時,將此約束應用于類型參數。
注意:new作為約束和其他約束共存時,必須在最后指定。
其定義方式為:
????class?Genericer<T>?where?T?:?new()????{
????????public?T?GetItem()
????????{
????????????return?new?T();
????????}
????}
?
實現方式為:
?
????class?MyCls????{
????????private?string?_name;
????????public?string?Name
????????{
????????????get?{?return?_name;?}
????????????set?{?_name?=?value;?}
????????}
????????public?MyCls()
????????{
????????????_name?=?"Emma";
????????}
????}
?
????class?MyGenericTester????{
????????public?static?void?Main(string[]?args)
????????{
????????????Genericer<MyCls>?MyGen?=?new?Genericer<MyCls>();
????????????Console.WriteLine(MyGen.GetItem().Name);
????????}
????}
- 使用new實現多態。 這不是我熟悉的話題,詳細的內容可以參見?《多態與 new [C#]》,這里有較詳細的論述。
3. 深入淺出
作為修飾符和約束的情況,不是很難理解的話題,正如我們看到本文開篇提出的問題,也大多集中在new作為運算符的情況,因此我們研究的重點就是揭開new作為運算符的前世今生。
Jeffrey Richter在其著作中,極力推薦讀者使用ILDASM工具查看IL語言細節,從而提高對.NET的深入探究,在我認為這真是一條不錯的建議,也給了自己很多提高的空間挖掘。因此,以下是本人的一點建議,我將在后續的系列中,關于學習方法論的討論中深入探討,這里只是順便小議,希望有益于大家。
1 不斷的學習代碼;
2 經常看看IL語言的運行細節,對于提供.NET的認識非常有效。
文歸正題,new運算符用于返回一個引用,指向系統分配的托管堆的內存地址。因此,在此我們以Reflector工具,來了解以下new操作符執行的背后,隱藏著什么玄機。
首先我們實現一段最簡單的代碼,然后分析其元數據的實現細節,來探求new在創建對象時到做了什么??
new作為運算符?
使用Reflector工具反編譯產生的IL代碼如下為:?
IL元數據分析?
從而可以得出以下結論:
- new一個class時,new完成了以下兩個方面的內容:一是調用newobj命令來為實例在托管堆中分配內存;二是調用構造函數來實現對象初始化。
- new一個struct時,new運算符用于調用其帶構造函數,完成實例的初始化。
- new一個int時,new運算符用于初始化其值為0。
- 另外必須清楚,值類型和引用類型在分配內存時是不同的,值類型分配于線程的堆棧(stack)上,并變量本身就保存其實值,因此也不受GC的控制,;而引用類型變量,包含了指向托管堆的引用,內存分配于托管堆(managed heap)上,內存收集由GC完成。?
另外還有以下規則要多加注意:
- new運算符不可重載。
- new分配內存失敗,將引發OutOfMemoryException異常。?
對于基本類型來說,使用new操作符來進行初始化的好處是,某些構造函數可以完成更優越的初始化操作,而避免了不高明的選擇,例如:
string?str?=?new?string('*',?100);string?str?=?new?string(new?char[]?{'a',?'b',?'c'});
?
?
而不是
string?str?=?"***************************************";??
4. 結論
??? 我能說的就這么多了,至于透了沒透,作者的能量也就這么多了。希望園子的大牛們常來扔塊磚頭,對我也是一種莫大的促進。但是作為基本的原理和應用,我想對大部分的需求是滿足了。希望這種力求深入淺出的介紹,能給你分享new關鍵字和其本質的來龍去脈能有所幫助。?
言歸正傳,開篇的幾個題目,不知讀者是否有了各自的答案,我們不妨暢所欲言,做更深入的討論,以便揭開其真實的面紗。?
參考文獻
(USA)Stanley B.Lippman, C# Primer
(USA)David Chappell Understanding .NET
?
廣而告之
[預告]
另外鑒于前幾個主題的討論中,不管是類型、關鍵字等都涉及到引用類型和值類型的話題,我將于近期發表相關內容的探討,同時還有其他的關鍵字值得研究,這是本系列近期動向,給自己做個廣告。祝各位愉快。?
[聲明]?
本文的關鍵字new指的是C#中的關鍵字概念,并非一般意義上的.NET CRL范疇,之所以將這個主題加入本系列,是基于在.NET體系下開發的我們,何言能逃得過基本語言的只是要點。所以大可不必追究什么是.NET,什么是C#的話題,希望大家理清概念,有的放肆。
總結
以上是生活随笔為你收集整理的[你必须知道的.NET] 第五回:深入浅出关键字---把new说透的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 今年第一批储蓄国债要来了!收益或胜过大部
- 下一篇: 美债遭海外买家大量抛售,我国债券却获外资