【C#小知识】C#中一些易混淆概念总结(四)---------解析Console.WriteLine()

简介:

目录:

【C#小知识】C#中一些易混淆概念总结

【C#小知识】C#中一些易混淆概念总结(二)

【C#小知识】C#中一些易混淆概念总结(三)

----------------------------------分割线--------------------------------------


这几天在温习结构体和类的时候遇到一个问题。发现一个奇怪的现象,一直找不到合理的答案。但是今天终于找到了合理的答案,所以拿来和大家分享一下。

我们首先来看下面的一段代码:

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
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; }
         //}
     }


当我们只是声明一个类和一个结构体的时候,我们的编译器顺利的编译通过。并且打印出结果如下:

051503145664566.png


为什么我们没有在结构和类中做任何操作,却可以打印出结果,且是“命名空间+"."+数据类型”呢?


首先我查阅了MSDN的关于结构(struct)的官方文档(地址点击这里),有如下的一段话:

051555260371652.png


结构默认的构造函数(如果没有显式声明)在实例化的时候才会被调用。所以,

1
2
3
4
//结构的实例化可以不使用NEW关键字,只是将p加载到栈空间中,但是对象不可用,这里没有调用默认的构造函数        
Point p2;         
Console.WriteLine(p2);       
Console.ReadKey();

在内存中是如下的情况:

060140117898884.png


此时在栈中已经存在了p这个对象,但是不可用。


那么为什么会打印出“命名空间+"."+数据类型”的结果呢?

我们先看一下VS编译后的中间代码,即Msil,详细解释在图中给出:

060214334159679.png


有中间语言代码,我们可以知道,最后调用的是Console.WriteLine(Object)方法


这时候就要深入的研究一下Console类了,用反编译工具.NET Reflector查看Console类,因为在上面的代码中,传进.WriteLine()方法的是一个类,所以,我们要查看它的的(object value)方法,如下图:

051515324938989.png


这时候,我们再深入到WriteLine()方法中去,源代码,如下:

051518095387242.png


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

051527119415340.png

因为p已经在栈中创建了对象(但是不可用),所以,直接进入else语句。


明显的可以发现IFormattable是一个接口,我们再看IFormattable接口的源码,如下:

051657238827557.png


显然我们的Point 结构没有实现一个ToString()方法,不存在继承关系,所以会转化失败,返回一个null值,又进入下一个else语句

else

 {          

this.WriteLine(value.ToString());    

  }

这时候最重要的就要来了,我们看到value值被转换为字符串输出了,在看ToString()源代码,如下:

051703271317515.png


很明显的发现,是获取该对象的数据类型并且转化为字符串输出。如下代码:

1
2
3
4
5
6
7
8
9
Point p;
             //打印出p的数据类型
             Console.WriteLine(p.GetType());
             Point p2;
             Console.WriteLine(p2);
            //使用NEW实例化了对像,调用了默认的构造函数
             Point p1 =  new  Point();
             Console.WriteLine(p1);
             Console.ReadKey();


打印结果:

051709389834982.png



这样对结构和类的了解有没有更深入的了解呢?




     本文转自yisuowushinian 51CTO博客,原文链接:http://blog.51cto.com/yisuowushinian/1356882 ,如需转载请自行联系原作者



相关文章
|
2月前
|
开发框架 容器
SAP UI5 控件的 aggregation 的概念解析
SAP UI5 控件的 aggregation 的概念解析
36 0
|
6天前
|
XML C# 数据格式
C# 解析XML文件
C# 解析XML文件
14 1
|
1月前
|
Python
继承概念深度解析:代码视角下的科普之旅
继承概念深度解析:代码视角下的科普之旅
6 0
|
1月前
|
存储 编解码 算法
音视频编程ffmepg中的关键术语与概念:深度解析与实践(二)
音视频编程ffmepg中的关键术语与概念:深度解析与实践
59 0
|
1月前
|
存储 编解码 网络协议
音视频编程ffmepg中的关键术语与概念:深度解析与实践(一)
音视频编程ffmepg中的关键术语与概念:深度解析与实践
72 0
|
1月前
|
数据库 数据库管理
构建信息蓝图:概念模型与E-R图的技术解析
构建信息蓝图:概念模型与E-R图的技术解析
29 0
|
2月前
|
并行计算 API 计算机视觉
Python多线程与多进程:概念、区别及应用场景解析
Python多线程与多进程:概念、区别及应用场景解析
|
1月前
|
C#
24. C# 编程:用户设定敌人初始血值的实现
24. C# 编程:用户设定敌人初始血值的实现
20 0
|
2月前
|
SQL 数据库连接 应用服务中间件
C#WinForm基础编程(三)
C#WinForm基础编程
77 0
|
2月前
C#WinForm基础编程(二)
C#WinForm基础编程
58 0

推荐镜像

更多