目录:html
----------------------------------分割线--------------------------------------工具
这几天在温习结构体和类的时候遇到一个问题。发现一个奇怪的现象,一直找不到合理的答案。可是今天终于找到了合理的答案,因此拿来和你们分享一下。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();
打印结果:
这样对结构和类的了解有没有更深刻的了解呢?