天天看点

【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,如需转载请自行联系原作者