转载:http://www.cnblogs.com/TianFang/p/3928172.html

所谓语法糖就是在编译器里写做文章,达到简化代码书写的目的,要慎重使用,省略过多不易理解。

NULL检查运算符(Monadic null checking)

这个是我非常喜欢的一个语法,例如我们要获取一个Point序列的第一个点的X坐标,第一感觉会这么写:

int firstX = points.First().X;

但是,老鸟会告诉你,这儿没有进行NULL检查,正确的版本是这样的:

int? firstX = null;     if (points != null)     {         var first = points.FirstOrDefault();         if (first != null)             firstX = first.X;     }

正确倒是正确了,代码取变得难读多了。现在,在C# 6.0中,引入了一个 ?. 的运算符,前面的代码可以改成如下形式:

int? firstX = points?.FirstOrDefault()?.X;

从这个例子中我们也可以看出它的基本用法:如果对象为NULL,则不进行后面的获取成员的运算,直接返回NULL

需要注意的是,由于"?."运算符返回的可以是NULL,当返回的成员类型是struct类型的时候,"?."和"."运算符的返回值类型是不一样的。

Point p = new Point(3, 2);     Console.WriteLine(p.X.GetType() == typeof(int));        //true     Console.WriteLine(p?.X.GetType() == typeof(int?));        //true

另外,除了"?."运算符外,还有一个"?[]"运算符,以使得我们可以写出如下表达式:

int? first = customers?[0].Orders.Count();

属性表达式(Property Expressions)

我们常常会在类中写一些通过函数生成的只读属性:

class Point     {         public int X { get; set; }         public int Y { get; set; }
        public Point(int x, int y)         {             this.X = x;             this.Y = y;         }
        public double Distance         {             get { return Math.Sqrt((X * X) + (Y * Y)); }         }         public Point Move(int dx, int dy)         {             return new Point(X + dx, Y + dy);         }     }

现在,可以利用一个Lambda表达式简化这一过程:

public double Distance => Math.Sqrt((X * X) + (Y * Y));

函数表达式(Method Expressions)

函数表达式和属性表达式比较类似,使得我们可以通过Lambda表达式简化成员函数。还是以上面的Point为例,Move函数可以简化如下

public Point Move(int dx, int dy) => new Point(X + dx, Y + dy);

最后,再总结前文介绍的几个新特性来一起来简化Point类:

class Point(int x, int y)     {         public int X { get; set; } = x;         public int Y { get; set; } = y;
        public double Distance => Math.Sqrt((X * X) + (Y * Y));
        public Point Move(int dx, int dy) => new Point(X + dx, Y + dy);     }

nameof表达式(Nameof expressions)

我们常常在反射或类似的技术中以字符串的形式使用属性的名称,抛开拼写错误不谈,当我们进行重构而修改属性名称的时候,由于字符串类型的属性得不到编译器检查,修改相应的字符串属性名称是一件非常令人头痛的事情,现在有了nameof,再也不用担心拼错属性名称了。

nameof运算符可以作用于变量、函数、类以及名字空间中,用于返回返回其名称,例如:

static void Main(string[] args)     {         Console.WriteLine(nameof(Main));        //输出 "Main"     }

当其参数是由"."运算符拼接起来的时候,只返回最后的名称,例如:

Console.WriteLine(nameof(ConsoleApplication1.Program));        //输出 "Program"

这个也可以理解,因为ConsoleApplication1.Program和Program本身就是等价的。

需要注意的是,由于C#允许函数重载,因此是存在同名函数的,例如:

static void foo() { }     static void foo(int x) { }

这样就存在如下两个问题:

  1. 转到定义应该跳到那个函数? 
  2. 当对其中的某个函数重命名,另一个函数维持原名称的时候, 使用nameof的地方是否也需要变化?

这两个问题只是体现在VisualStudio上,并不是语法的歧义,也不影响运行结果。在CodePlex中也有专门的文章讨论它,目前的处理方式是:

  1. 转到定义应该跳到那个函数?     (谁先定义转到谁)
  2. 当对其中的某个函数重命名,另一个函数维持原名称的时候, 使用nameof的地方是否也需要变化? (重命名函数不重命名nameof,其它的类型如属性等重命名会一起变化)

catch和finally语句块中支持await

在C# 5.0中引入了await运算符,可以方便我们执行异步运算。当时其并不能在catch和finally中使用,让人有点意犹未尽的感觉。在C# 6.0放开了这一限制,使用更加方便了。

try     {         res = await Resource.OpenAsync(…);     }     catch (ResourceException e)     {         await Resource.LogAsync(res, e);    //现在支持了     }     finally     {         if (res != null) await res.CloseAsync(); //现在也支持了     }

catch支持筛选条件了

catch支持筛选条件也是呼声比较高的特性之一,现在终于可以省得重新再抛一次了

try     {         foo();     }     catch (Exception e ) if (e.HResult == 0x800000C)     {         //do something     }

主构造函数(Primary Constructors)

我们通常通过构造函数给属性赋初值,一个常见的例子如下:

class Point     {         public int X { get; set; }         public int Y { get; set; }
        public Point(int x, int y)         {             this.X = x;             this.Y = y;         }     }

现在, 通过过给类定义一个主构造函数,我们可以简化代码如下:

class Point(int x, int y)     {         public int X { get; set; } = x;         public int Y { get; set; } = y;     }

或者给只读属性附初值

class Point(int x, int y)     {         public int X { get; } = x;         public int Y { get; } = y;     }

其实这儿不限于属性,字段也可以也这种方式初始化。

自动属性初始化器

这个则是VB中已经有的一个语法,在当前的C#语法中,要给一个属性赋自动初值,一般有两种方式:

1. 在构造函数中:

class Point     {         public int X { get; private set; }         public int Y { get; private set; }
        public Point()         {             this.X = 100;             this.Y = 100;         }     }

2. 使用属性封装

class Point     {         int x = 100;         public int X         {             get { return x; }             private set { x = value; }         }
        int y = 100;         public int Y         {             get { return y; }             private set { y = value; }         }     }

使用自动属性初始化时,代码则可简化如下:

class Point     {         public int X { get; private set; } = 100;         public int Y { get; private set; } = 100;     }

using静态类(Static type using statements)

这个也是一个VB的特性了,在加上using 静态类的声明后,我们就可以不通过类名直接调用函数了,例如,如下代码:

Math.Sqrt(Math.Round(5.142));

可以简化如下:

using System.Math;     Sqrt(Round(5.142));

如果在大量使用数学运算的时候看起来要舒服得多了。

内联out参数定义(Inline declarations for out params)

这个是我非常喜欢的一个特性。以前有out参数的地方的时候,必须先声明一个临时变量,如下所示:

int x;     int.TryParse("123", out x);

现在我们则可以把它写成如下形式了:

int.TryParse("123", out var x);

就算需要out参数的返回值也可以一行代码搞定:

var result = int.TryParse("123", out var x) ? x : 0;

成员索引(Indexed members)

这个语法之前倒是没有看到介绍,主要实现的是以类似成员的方式访问索引,示例如下:

class MyClass     {         public string this[string index]         {             get { return "hello " + index; }         }

public void foo()         {             var result = this.$world;             Console.WriteLine(result);        //这里输出 hello world         }     }

其它特性

官方的特性实现状态文档:http://roslyn.codeplex.com/wikipage?title=Language%20Feature%20Status&referringTitle=Home

C# 6.0新特性---语法糖的更多相关文章

  1. C# 7.0 新特性1: 基于Tuple的“多”返回值方法

    本文基于Roslyn项目中的Issue:#347 展开讨论. 1. C# 7.0 新特性1: 基于Tuple的“多”返回值方法 2. C# 7.0 新特性2: 本地方法 3. C# 7.0 新特性3: ...

  2. C# 7.0 新特性3: 模式匹配

    本文参考Roslyn项目Issue:#206,及Docs:#patterns. 1. C# 7.0 新特性1: 基于Tuple的“多”返回值方法 2. C# 7.0 新特性2: 本地方法 3. C# ...

  3. [C#]6.0新特性浅谈

    原文:[C#]6.0新特性浅谈 C#6.0出来也有很长一段时间了,虽然新的特性和语法趋于稳定,但是对于大多数程序猿来说,想在工作中用上C#6.0估计还得等上不短的一段时间.所以现在再来聊一聊新版本带来 ...

  4. C# 7.0 新特性:本地方法

    C# 7.0:本地方法 VS 2017 的 C# 7.0 中引入了本地方法,本地方法是一种语法糖,允许我们在方法内定义本地方法.更加类似于函数式语言,但是,本质上还是基于面向对象实现的. 1. 本地方 ...

  5. Kotlin 特性 语法糖 优势 扩展 高阶 MD

    Markdown版本笔记 我的GitHub首页 我的博客 我的微信 我的邮箱 MyAndroidBlogs baiqiantao baiqiantao bqt20094 baiqiantao@sina ...

  6. C# 9.0 新特性预览 - 类型推导的 new

    C# 9.0 新特性预览 - 类型推导的 new 前言 随着 .NET 5 发布日期的日益临近,其对应的 C# 新版本已确定为 C# 9.0,其中新增加的特性(或语法糖)也已基本锁定,本系列文章将向大 ...

  7. C# 9.0 新特性预览 - 空参数校验

    C# 9.0 新特性预览 - 空参数校验 前言 随着 .NET 5 发布日期的日益临近,其对应的 C# 新版本已确定为 C# 9.0,其中新增加的特性(或语法糖)也已基本锁定,本系列文章将向大家展示它 ...

  8. C# 9.0 新特性预览 - 顶级语句

    C# 9.0 新特性预览 - 顶级语句 前言 随着 .NET 5 发布日期的日益临近,其对应的 C# 新版本已确定为 C# 9.0,其中新增加的特性(或语法糖)也已基本锁定,本系列文章将向大家展示它们 ...

  9. C# 9.0 新特性预览 - init-only 属性

    C# 9.0 新特性预览 - init-only 属性 前言 随着 .NET 5 发布日期的日益临近,其对应的 C# 新版本已确定为 C# 9.0,其中新增加的特性(或语法糖)也已基本锁定,本系列文章 ...

随机推荐

  1. 【经验之谈】Git使用之Windows环境下配置

    前言 安装 配置 关于git使用的几个问题 后记 关于代码托管,以前用过vss和svn,看博客或论坛的时候,经常有人提到github,有很多著名的开源软件都托管在github,想来肯定不错(莫笑),当 ...

  2. C++ 制作 json 数据 并 传送给服务端(Server) 的 php

    json数据格式,这里举个基础的例子: {"name":"LGH"} 在C++里面,我用个函数把特定的数据组合成 json void toJson(int co ...

  3. 重温Servlet学习笔记--response对象

    在用户浏览网页时,服务器对于客户端浏览器做出的响应被封装成一个HttpServletResponse对象,要对浏览器操作只需要操作这个response对象即可.response的功能分类及介绍: 响应 ...

  4. Electron Angular 开发小记

    一介绍 electron分为主进程和渲染进程,主进程负责和原生交互,控制窗口等. 渲染进程就是普通网页.主进程和渲染进程可以通过ipcMain(主进程使用)及ipcRenderer(渲染进程用)通信 ...

  5. 《Kafka Stream》调研:一种轻量级流计算模式

    原文链接:https://yq.aliyun.com/articles/58382 摘要: 流计算,已经有Storm.Spark,Samza,包括最近新起的Flink,Kafka为什么再自己做一套流计 ...

  6. 简单粗暴,详细得不要不要的 JavaWeb快速入门实例(1)

    额,有些标题党的嫌疑,小细节不用在意哈... 前端时间我在写一个系列,是关于JavaWeb的一个入门级项目实战,我的初衷就是打算写给初学者的,希望能对他们有所帮助. 这段时间博主也接触了一些事情,感觉 ...

  7. 在新浪云SAE中使用smarty引擎模版

    在新浪云上使用smarty时会发现又这样的错误信息: “SAE_Fatal_error: Uncaught exception 'SmartyException' with message 'unab ...

  8. 【Win10开发】处理PC上的后退键

    我们知道在win10手机上和平板上都会有后退键,那么PC上该怎么办呢?没关系我们慢慢揭晓. 如果你已经是UWP的忠实用户,那么肯定会见到如下的后退键. 那么我们如何来做出来呢?, 我们首先打开App. ...

  9. Hibernate框架与Mybatis框架的对比

    学习了Hibernate和Mybatis,但是一直不太清楚他们两者的区别的联系,今天在网上翻了翻,就做了一下总结,希望对大家有帮助! 原文:http://blog.csdn.net/firejuly/ ...

  10. Entity Framework 代码先行

    一.什么是Code First 为了支持以设计为中心的开发流程,EF还更多地支持以代码为中心 (code-centric) ,我们称为代码优先的开发,代码优先的开发支持更加优美的开发流程,它允许你在不 ...