【C#小知識】C#中一些易混淆概念總結(四)---------解析Console.WriteLine()

目錄:html

【C#小知識】C#中一些易混淆概念總結函數

【C#小知識】C#中一些易混淆概念總結(二)

【C#小知識】C#中一些易混淆概念總結(三)

----------------------------------分割線--------------------------------------工具

 

這幾天在溫習結構體和類的時候遇到一個問題。發現一個奇怪的現象,一直找不到合理的答案。可是今天終於找到了合理的答案,因此拿來和你們分享一下。post

咱們首先來看下面的一段代碼:this

class Program { static void Main(string[] args) {  Point p; Console.WriteLine(p); Point p1 = new Point(); Console.WriteLine(p1); Console.ReadKey(); } } //定義結構
    struct Point { ////定義時賦初始值,編譯器會報錯
        //private int x; //public Point() //{ }
 } class Person { //在類中咱們能夠爲屬性賦初始值 //private int nAge = 5; //public int NAge //{ // get { return nAge; } // set { nAge = value; } //}
 }

 

當咱們只是聲明一個類和一個結構體的時候,咱們的編譯器順利的編譯經過。而且打印出結果以下:url

 

爲何咱們沒有在結構和類中作任何操做,卻能夠打印出結果,且是「命名空間+"."+數據類型」呢?spa

 

首先我查閱了MSDN的關於結構(struct)的官方文檔(地址點擊這裏),有以下的一段話:code

 

結構默認的構造函數(若是沒有顯式聲明)在實例化的時候纔會被調用。因此,   orm

        //結構的實例化能夠不使用NEW關鍵字,只是將p加載到棧空間中,可是對象不可用,這裏沒有調用默認的構造函數
 Point p2; Console.WriteLine(p2);  Console.WriteLine(p2); Console.ReadKey();

在內存中是以下的狀況:htm

 

此時在棧中已經存在了p這個對象,可是不可用。

 

那麼爲何會打印出「命名空間+"."+數據類型」的結果呢?

咱們先看一下VS編譯後的中間代碼,即Msil,詳細解釋在圖中給出:

 

有中間語言代碼,咱們能夠知道,最後調用的是Console.WriteLine(Object)方法

 

這時候就要深刻的研究一下Console類了,用反編譯工具.NET Reflector查看Console類,由於在上面的代碼中,傳進.WriteLine()方法的是一個類,因此,咱們要查看它的的(object value)方法,以下圖:

 

這時候,咱們再深刻到WriteLine()方法中去,源代碼,以下:

 

再看Out.WriteLine()的源代碼:

由於p已經在棧中建立了對象(可是不可用),因此,直接進入else語句。

 

明顯的能夠發現IFormattable是一個接口,咱們再看IFormattable接口的源碼,以下:

 

顯然咱們的Point 結構沒有實現一個ToString()方法,不存在繼承關係,因此會轉化失敗,返回一個null值,又進入下一個else語句

else { this.WriteLine(value.ToString()); }

這時候最重要的就要來了,咱們看到value值被轉換爲字符串輸出了,在看ToString()源代碼,以下:

 

很明顯的發現,是獲取該對象的數據類型而且轉化爲字符串輸出。以下代碼:

        Point p; //打印出p的數據類型
 Console.WriteLine(p.GetType()); Point p2; Console.WriteLine(p2); //使用NEW實例化了對像,調用了默認的構造函數
            Point p1 = new Point(); Console.WriteLine(p1); Console.ReadKey();

 

打印結果:

 

 

這樣對結構和類的瞭解有沒有更深刻的瞭解呢?

相關文章
相關標籤/搜索