在线时间:8:00-16:00
迪恩网络APP
随时随地掌握行业动态
扫描二维码
关注迪恩网络微信公众号
转载: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; } 现在,可以利用一个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;
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) { } 这样就存在如下两个问题:
这两个问题只是体现在VisualStudio上,并不是语法的歧义,也不影响运行结果。在CodePlex中也有专门的文章讨论它,目前的处理方式是:
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; } 现在, 通过过给类定义一个主构造函数,我们可以简化代码如下: 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; } 2. 使用属性封装 class Point { int x = 100; public int X { get { return x; } private set { x = 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; } }
其它特性 官方的特性实现状态文档:http://roslyn.codeplex.com/wikipage?title=Language%20Feature%20Status&referringTitle=Home。 所谓语法糖就是在编译器里写做文章,达到简化代码书写的目的,要慎重使用,省略过多不易理解。
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; } 现在,可以利用一个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;
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) { } 这样就存在如下两个问题:
这两个问题只是体现在VisualStudio上,并不是语法的歧义,也不影响运行结果。在CodePlex中也有专门的文章讨论它,目前的处理方式是:
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; } 现在, 通过过给类定义一个主构造函数,我们可以简化代码如下: 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; } 2. 使用属性封装 class Point { int x = 100; public int X { get { return x; } private set { x = value; } } |
请发表评论