天天看點

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

目錄:

<a href="http://www.cnblogs.com/qq731109249/p/3525271.html" target="_blank"></a>

<a href="http://yisuowushinian.blog.51cto.com/4241271/1352834" target="_blank">【C#小知識】C#中一些易混淆概念總結</a>

----------------------------------分割線--------------------------------------

這幾天在溫習結構體和類的時候遇到一個問題。發現一個奇怪的現象,一直找不到合理的答案。但是今天終于找到了合理的答案,是以拿來和大家分享一下。

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

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

<code>class</code> <code>Program</code>

<code>    </code><code>{</code>

<code>        </code><code>static</code> <code>void</code> <code>Main(</code><code>string</code><code>[] args)</code>

<code>        </code><code>{</code>

<code>            </code><code>Point p;</code>

<code>            </code><code>Console.WriteLine(p);</code>

<code>                                               </code> 

<code>            </code><code>Point p1 = </code><code>new</code> <code>Point();</code>

<code>            </code><code>Console.WriteLine(p1);</code>

<code>            </code><code>Console.ReadKey();</code>

<code>        </code><code>}</code>

<code>    </code><code>}</code>

<code>    </code><code>//定義結構</code>

<code>    </code><code>struct</code> <code>Point</code>

<code>        </code><code>////定義時賦初始值,編譯器會報錯</code>

<code>        </code><code>//private int x;</code>

<code>        </code><code>//public Point()</code>

<code>        </code><code>//{ }</code>

<code>    </code><code>class</code> <code>Person</code>

<code>        </code><code>//在類中我們可以為屬性賦初始值</code>

<code>        </code><code>//private int nAge = 5;</code>

<code>        </code><code>//public int NAge</code>

<code>        </code><code>//{</code>

<code>        </code><code>//    get { return nAge; }</code>

<code>        </code><code>//    set { nAge = value; }</code>

<code>        </code><code>//}</code>

當我們隻是聲明一個類和一個結構體的時候,我們的編譯器順利的編譯通過。并且列印出結果如下:

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

為什麼我們沒有在結構和類中做任何操作,卻可以列印出結果,且是“命名空間+"."+資料類型”呢?

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

結構預設的構造函數(如果沒有顯式聲明)在執行個體化的時候才會被調用。是以,

<code>//結構的執行個體化可以不使用NEW關鍵字,隻是将p加載到棧空間中,但是對象不可用,這裡沒有調用預設的構造函數        </code>

<code>Point p2;         </code>

<code>Console.WriteLine(p2);       </code>

<code>Console.ReadKey();</code>

在記憶體中是如下的情況:

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

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

那麼為什麼會列印出“命名空間+"."+資料類型”的結果呢?

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

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

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

這時候就要深入的研究一下Console類了,用反編譯工具.NET Reflector檢視Console類,因為在上面的代碼中,傳進.WriteLine()方法的是一個類,是以,我們要檢視它的的(object value)方法,如下圖:

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

這時候,我們再深入到WriteLine()方法中去,源代碼,如下:

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

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

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

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

明顯的可以發現IFormattable是一個接口,我們再看IFormattable接口的源碼,如下:

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

顯然我們的Point 結構沒有實作一個ToString()方法,不存在繼承關系,是以會轉化失敗,傳回一個null值,又進入下一個else語句

else

 {          

this.WriteLine(value.ToString());    

  }

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

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

很明顯的發現,是擷取該對象的資料類型并且轉化為字元串輸出。如下代碼:

<code>Point p;</code>

<code>            </code><code>//列印出p的資料類型</code>

<code>            </code><code>Console.WriteLine(p.GetType());</code>

<code>            </code><code>Point p2;</code>

<code>            </code><code>Console.WriteLine(p2);</code>

<code>           </code><code>//使用NEW執行個體化了對像,調用了預設的構造函數</code>

列印結果:

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

這樣對結構和類的了解有沒有更深入的了解呢?

     本文轉自yisuowushinian 51CTO部落格,原文連結:http://blog.51cto.com/yisuowushinian/1356882,如需轉載請自行聯系原作者