C# 6.0新特性---语法糖
转载: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) { }
这样就存在如下两个问题:
- 转到定义应该跳到那个函数?
- 当对其中的某个函数重命名,另一个函数维持原名称的时候, 使用nameof的地方是否也需要变化?
这两个问题只是体现在VisualStudio上,并不是语法的歧义,也不影响运行结果。在CodePlex中也有专门的文章讨论它,目前的处理方式是:
- 转到定义应该跳到那个函数? (谁先定义转到谁)
- 当对其中的某个函数重命名,另一个函数维持原名称的时候, 使用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新特性---语法糖的更多相关文章
- C# 7.0 新特性1: 基于Tuple的“多”返回值方法
本文基于Roslyn项目中的Issue:#347 展开讨论. 1. C# 7.0 新特性1: 基于Tuple的“多”返回值方法 2. C# 7.0 新特性2: 本地方法 3. C# 7.0 新特性3: ...
- C# 7.0 新特性3: 模式匹配
本文参考Roslyn项目Issue:#206,及Docs:#patterns. 1. C# 7.0 新特性1: 基于Tuple的“多”返回值方法 2. C# 7.0 新特性2: 本地方法 3. C# ...
- [C#]6.0新特性浅谈
原文:[C#]6.0新特性浅谈 C#6.0出来也有很长一段时间了,虽然新的特性和语法趋于稳定,但是对于大多数程序猿来说,想在工作中用上C#6.0估计还得等上不短的一段时间.所以现在再来聊一聊新版本带来 ...
- C# 7.0 新特性:本地方法
C# 7.0:本地方法 VS 2017 的 C# 7.0 中引入了本地方法,本地方法是一种语法糖,允许我们在方法内定义本地方法.更加类似于函数式语言,但是,本质上还是基于面向对象实现的. 1. 本地方 ...
- Kotlin 特性 语法糖 优势 扩展 高阶 MD
Markdown版本笔记 我的GitHub首页 我的博客 我的微信 我的邮箱 MyAndroidBlogs baiqiantao baiqiantao bqt20094 baiqiantao@sina ...
- C# 9.0 新特性预览 - 类型推导的 new
C# 9.0 新特性预览 - 类型推导的 new 前言 随着 .NET 5 发布日期的日益临近,其对应的 C# 新版本已确定为 C# 9.0,其中新增加的特性(或语法糖)也已基本锁定,本系列文章将向大 ...
- C# 9.0 新特性预览 - 空参数校验
C# 9.0 新特性预览 - 空参数校验 前言 随着 .NET 5 发布日期的日益临近,其对应的 C# 新版本已确定为 C# 9.0,其中新增加的特性(或语法糖)也已基本锁定,本系列文章将向大家展示它 ...
- C# 9.0 新特性预览 - 顶级语句
C# 9.0 新特性预览 - 顶级语句 前言 随着 .NET 5 发布日期的日益临近,其对应的 C# 新版本已确定为 C# 9.0,其中新增加的特性(或语法糖)也已基本锁定,本系列文章将向大家展示它们 ...
- C# 9.0 新特性预览 - init-only 属性
C# 9.0 新特性预览 - init-only 属性 前言 随着 .NET 5 发布日期的日益临近,其对应的 C# 新版本已确定为 C# 9.0,其中新增加的特性(或语法糖)也已基本锁定,本系列文章 ...
随机推荐
- Moon.Orm版本维护及下载(跟踪报道)
提示:最下面有最新的下载地址 历史记录: ).-- :: 支持Mysql,Sqlserver(点击下载) ).2013年9月14日,代码重构,加入oracle.复合主键功能(点击下载) )--,为d ...
- Vue.js说说组件
什么是组件:组件是Vue.js最强大的功能之一.组件可以扩展HTML元素,封装可重用的代码.在较高层面上,组件是自定义的元素,Vue.js的编译器为它添加特殊功能.在有些情况下,组件也可以是原生HTM ...
- [C#] 获取打印机列表
一:获得本地安装的打印机列表 注:(如果在"设备和打印机"中已经添加了局域网的打印机设备,也算是本地安装的打印机:没有添加的则算作局域网打印机) 1,通过 C# 中 Printer ...
- 关于WebBrowser访问百度地图
前段时间遇到一个困惑用WebBrowser访问百度地图的时候,百度会自动转至让下载sdk的页面,经过一个仁兄的点拨,可以改变WebBrowser的agent来骗过网站.经过试验成功.贴源码如下: st ...
- Java集合概述
容器,是用来装东西的,在Java里,东西就是对象,而装对象并不是把真正的对象放进去,而是指保存对象的引用.要注意对象的引用和对象的关系,下面的例子说明了对象和对象引用的关系. String str = ...
- SSH整合(struts2.3.24+hibernate3.6.10+spring4.3.2+mysql5.5+myeclipse8.5+tomcat6+jdk1.6)
终于开始了ssh的整合,虽然现在比较推崇的是,ssm(springmvc+spring+mybatis)这种框架搭配确实比ssh有吸引力,因为一方面springmvc本身就是遵循spring标准,所以 ...
- Java--通过Spring AOP进行事务管理
<?xml version="1.0" encoding="UTF-8"?> <beans xmlns="http://www.sp ...
- 深入Java关键字this的用法的总结
在Java程序设计中经常会见到this的使用,this使得程序设计变得规范.简单.灵活.但是在使用过程中,在不同场 合它的含义并不完全相同,使用不当还会出现错误, 本文对this的几种用法和出现的问题 ...
- [TypeScript] 建立与使用AMD Library
[TypeScript] 建立与使用AMD Library 前言 使用Visual Studio开发TypeScript项目时,开发人员可以将可重用的程序代码,封装为AMD Library来提供其他开 ...
- Three.js基础部分学习
一.关于使用Three.js几点理论说明 1.请参考官网地址 https://threejs.org/ 2.使用three.js必备条件 <场景 A scene.相机a camera.渲染器 a ...