博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
从反编译的角度去观察C#6.0
阅读量:6006 次
发布时间:2019-06-20

本文共 3023 字,大约阅读时间需要 10 分钟。

1. 自动属性初始化 (Initializers for auto-properties)

1.1 C#6.0 之前的写法

public class FirstExperience{   private string _stringAutoProp = "自动初始化属性";   public string StringAutoProp   {      get{ return _stringAutoProp; }      set{ _stringAutoProp = value; }   }}

1.2 C#6.0 中的写法

public class FirstExperience{   public string StringAutoProp { get; set; } = "自动初始化属性";}

1.3 反编译效果

764049-20150929195551324-1421113242.png

从反编译中我们发现多了个私有字段this.<StringAutoProp>k__BackingField;并在默认的构造函数中将“自动初始化属性”赋值给了这个字段,那么可以推断出IL中肯定会有这个匿名字段的定义,让我们再来看看IL中的体现:
764049-20150929195736777-1493330200.png

用上面的两张图我们可以得出以下结论

其实自动初始化属性就是在CLR中体现就是创建私有的匿名字段,然后在构造函数中为这个匿名属性赋值,而属性的getSet方法其实就是在操作这个匿名属性。

2. 只读属性的初始化(Getter-only auto-properties)

2.1 C#6.0 之前的写法

public FirstExperience(int id){    _id = id;}private readonly int _id;public int ID{    get { return _id; }}

2.2 C#6.0 中的写法

public int ReadonlyProp { get; }public FirstExperience(int _readonlyProp){    ReadonlyProp = _readonlyProp;}

2.3 反编译效果

764049-20150929195914949-1281184912.png

从反编译的结果我们看到构造函数中将传进来的_readonlyProp赋值给this.<ReadonlyProp>k__BackingField字段,而属性的get方法操作的就是这个由编译器生成的字段,而在ReadonlyProp属性的get方法中打了CompilerGenerated这个特性标签,这个标签其实就是区分编译器生成的元素与用户生成的元素,关于这个特性请移步到。由此可以推断IL中所做的操作与自动初始化属性一致

3. 用Lambda作为函数体 (Expression bodies on method-like members)

3.1 C# 6.0 之前的写法

public override string ToString(){    return string.Format("{0}",StringAutoProp);}

3.2 C# 6.0 写法

public override string ToString() => string.Format("{0}", StringAutoProp);

在6.0 语法中我们看到可以使用lambda表达式直接作为函数体,那么编译器到底为我们做了什么呢?

3.3 反编译效果

764049-20150929200556449-663279966.png

从反编译中我们可以看出编译器编译的时候把lambda函数直接编译成方法体,那么再看看IL的区别了。

764049-20150929200645918-9225414.png

764049-20150929200702371-441580455.png

从上面两张图中可以看出除了标注堆栈标注刻度不同以外,看不出有什么差别。我也不是太明白这个地方,求园内的大牛解释解释!

4. 空值判断 (Null-conditional operators)

4.1 恶心的写法

if(xxx !=null){    xxx.ToString();}

这种写法相信有非常多的朋友用过,经常为了一个是否为空的问题搞得代码非常难看,

举个栗子:我们需要获取集合或者是字符喘的长度

if(parem!=null){    return parem.Length;}return null;

这样的写法实在太恶心了,在6.0语法中我们可以这么写

public int? GetListCount(List
list){ return list?.Count();}

4.2 实际应用的栗子

在实际应用中,经常会用到委托,而在之前我们需要调用委托时则需要判断委托是否为空如下代码:

public void Test(TestNew test){    if (test != null)    {        test.Invoke();    }}

对于强迫症的我来说这样太恶心了,于是乎利用6.0的语法开始改造

public void Test1(TestNew test){    test?.Invoke();}

4.3 根据上面的栗子进行反编译

764049-20150929200920543-1421478641.png

从上图反编译效果可以看到两个方法基本没有差别,接下来看看IL中有什么差别:

764049-20150929200949886-1244017607.png

上图为6.0语法委托调用的IL图,发现核心还是brtrue.s做IF判断决定执行流

5. nameof表达式 (nameof expressions)

5.1 在实际项目的方法中我们经常需要这样去做参数判断

public void MyMethod(string name){    if (string.IsNullOrEmpty(name))    {        throw new ArgumentNullException("name");    }}

上面代码中的name是我们手写的字符串,在给参数name改名时经常会忘记改下面的字符串name,然而 6.0 解决了这个问题:

public void MyMethod(string name){    if (string.IsNullOrEmpty(name))    {        throw new ArgumentNullException(nameof(name));    }}

5.2 nameof的反编译

764049-20150929201250027-1735359925.png

上图中nameof(name)被替换成了字符串name,就如同常量一样。继续来看看IL做了什么:

764049-20150929201625590-340345438.png

从IL中我们可以看到它是直接ldstr,既不是反射也不是拿变量的内存值,在实际运用中有时候我们会通过Type来获取他的类名或者是直接写死的但是这样通过反编译后会发现Type.Name在IL中其实是通过反射来获取,而直接写死的方式,在IL中其实就是定义一个变量到堆栈中然后再引用进去。

nameof(name)具有这两种的的有点,灵活而且相对于type和写死的方式性能更高了。

6. 小结

其实6.0中还有很多新的语法糖,在这里就不一一介绍了,等不忙了,我在把其他的新的语法糖写出来

非常感谢您花时间读完这篇文章,如果您觉得此文不错,请点一下“推荐”按钮,您的“推荐”就是对我最大的鼓励以及不懈努力的肯定。 本文版权归作者和博客园所有,来源网址:欢迎各位转载,转载文章之后必须在文章页面明显位置给出作者和原文连接,否则保留追究法律责任的权利以及小小的鄙视。

转载于:https://www.cnblogs.com/Wesley-Zen/p/4847101.html

你可能感兴趣的文章
判断radiobutton是否被选中
查看>>
配置 SSH Key ☞ GitHub
查看>>
操作系统思考 第零章 前言
查看>>
kmdjs和循环依赖
查看>>
Handler 系列二:怎么通信
查看>>
WorkPlus JS SDK
查看>>
Elm 架构教程
查看>>
Android Studio工具修理集
查看>>
Markdown中超链接增加_blank的方法
查看>>
机器人都能造飞机了,你还在呼呼大睡?
查看>>
linux 内核的链表操作(好文不得不转)
查看>>
《泛在服务 ,平台创新》移动电商生态研究报告
查看>>
JVM学习系列:了解JVM options参数配置 & 看懂GC日志
查看>>
12C 对表分区维护的增强
查看>>
算术运算表达式正则及分析
查看>>
linux tcpdump
查看>>
如何实现文件增量同步——算法
查看>>
R.string获取的是数字或者R.integer数字不对的问题
查看>>
dpkg ---- apt-get ------ aptitude 三种方式的区别 及命令格式
查看>>
SQL Server 2008 R2 死锁监控
查看>>