C# 6以前咱们构建只读自动属性:web
1 public string FirstName { get; private set; } 2 public string LastName { get; private set; }
原理解析:就是编译器在生成set访问器时,它的修饰符是private,由上可知所谓的只读只是针对类外部,在类内部仍是能够随意修改属性值的。express
C# 6中提供了真正的只读自动属性,写法以下:编程
1 public string FirstName { get; } 2 public string LastName { get; }
原理解析:首先编译器会生成一个readonly的私有字段而get访问器就是返回该字段的值,由上可知该只读自动属性只能在构造函数中为其赋值。异步
之前自动属性的赋值操做咱们只能写在方法中,如构造函数:async
1 public Student(string firstName, string lastName) 2 { 3 FirstName = firstName; 4 LastName = lastName; 5 }
但在C# 6中咱们能够把赋值操做看成声明的一部份,以下所示:异步编程
1 public string FirstName { get; set; } = "Corleone"; 2 public string LastName { get; set; } = "Mike";
备注:其实C# 6和以前的版本都同样赋值操做最终都是在方法中完成,但后者明显更简洁直观,因此这是个不错的语法糖。函数
C# 6中提供的一个新语法:对于只有一条语句的方法体能够简写成表达式。以下面两种状况:spa
1. 方法(Methods).net
1 public Student Create() => new Student();
等同于:设计
1 public Student Create() 2 { 3 return new Student(); 4 }
2. 只读属性(read only properties)
1 public string FullName => string.Format("{0},{1}", FirstName, LastName);
等同于:
1 public string FullName 2 { 3 get 4 { 5 return string.Format("{0},{1}", FirstName, LastName); 6 } 7 }
原理解析:上面的表达式在编译后会生成最原始的方法体和访问器,值得一提的是函数表达式体跟Lambda是两个类似但不相同的东西,函数的表
达式体只能带一句话且不能包含return关键字但Lambda 能带语句块和包含关键字。
C# 6中的一个新语法:使用类型的静态成员时能够省略其类型,以下所示:
1 using static System.String; // 先导入对应成员类型 2 public bool IsNull(string str) => IsNullOrEmpty(str);
等同于:
1 public bool IsNull(string str) => string.IsNullOrEmpty(str);
总结:该语法糖的目的是使代码变得更简洁,但这个应该是区分使用场景的,如:数学计算(Math类)使用此语法糖的确可以简洁代码提升可读
性,但在某处若是导入过多的类型那么不只不能提升阅读性反而会增长阅读难度,由于你不知道这些成员具体属于那个类型。还有若类型自己存在
同名成员使用时则会使用类型成员覆盖。
注意:使用静态这一语法糖并不适用扩展方法,由于扩展方法的设计理念就是不修改已有代码且只能在必定范围内使用,因此在特殊状况下须要将
其看成静态方法来使用,那么使用类名调用反而是比较明智的。
稍有经验的童鞋都知道在Coding过程当中常常要判断变量的值是否为null,相似这种if-else的操做还很多。这使得代码看起来十分不简洁,好在C#6
中提供了解决方法:
1 var student = new Student(); 2 var firstName = student?.FirstName;
等同于:
1 var student = new Student(); 2 3 string firstName = null; 4 if (student != null) 5 { 6 firstName = student.FirstName; 7 }
使用方法:只需替换成员访问符 . 为 ?. ,若 ?. 左边为null则整个运算符的结果也为null,不然运算符的结果就等于其成员值。假如成员的类型为值
类型则整个表达式返回的类型是对应类型的可空类型,如:
1 int? age = student?.Age;
原理解析: ?. 编译后就是 if 或 三元运算符,非赋值操做(如:call)会编译成 if,赋值操做通常会编译成三元运算符。
C# 6中提供了一种新语法来构建格式化字符串,如:
1 var fullName = $"{student.FirstName},{student.LastName}";
等同于:
1 var fullName = string.Format("{0},{1}", student.FirstName, student.LastName);
使用方法:只需在字符串前加上$符号,而后在大括号中填写表达式(字段、方法、Lambdad...)便可。
备注:
1. 字符串插值语法支持之前全部字符串格式设置(此项仅支持 .net framework,不支持 .net core 1.0.1),如:
1 Console.WriteLine($"平均成绩:{student.GPA:F2}");
注:由于 : 总被编译器解释为表达式与字符串格式的分隔符,因此表达式中如有条件运算符则咱们须要用括号来强制编译将其解析成当前语境所要
表达的意义。如:
1 Console.WriteLine($"平均成绩:{(student.GPA > 80 ? student.GPA : 0):F2}");
2. 字符串插值语法能够嵌套,如:
1 var score = $"个人各科成绩:{ $"数学:{student.MathScores};英语:{student.EnglishScore};"}";
原理解析:$"xxx{expression1}xxx{expression2}..." 编译后就是string.Format()。
C# 6中的一个新功能就是异常过滤器,它可使咱们在恰当的时机来应用Catch子句,如:
1 try 2 { 3 throw new WebException("Request timed out..", WebExceptionStatus.Timeout); 4 } 5 catch (WebException webEx) when (webEx.Status == WebExceptionStatus.Timeout) 6 { 7 // Exception handling 8 }
使用方法:try-catch() when()。
总结:异常过滤器最大的亮点就是在使用恰当的状况下能够不丢失异常引起点的堆栈信息,这对程序的排错相当重要。另外它还有不少有意思的用
法,你们能够上网查下。
nameof 表达式的功能是获取成员名称,如抛异常:
1 public string FullName(Student student) 2 { 3 if (student == null) 4 throw new ArgumentNullException(nameof(student)); 5 6 return $"{student.FirstName},{student.LastName}"; 7 }
优势:nameof 表达式它可以理解成员,当成员被重命名时nameof表达式中也重命名了,而常量字符串表示法是没有这样的优点。
缺点:nameof 表达式生成的是不彻底限定名,若你须要彻底限定名 nameof 就不能帮你了。
原理解析:nameof 是编译期间就肯定其(成员)字符串名称的,即编译后就是常量字符串的表现形式了。
C# 5 提供的 async 和 await 使异步编程变得极为简便,但它们也有着局限性:await在catch和finally块中不能使用。但这个问题已在C# 6中获得
了解决,如:
1 public static async Task<string> MakeRequestAndLogFailures() 2 { 3 await logMethodEntrance(); 4 try 5 { 6 // .... 7 var responseText = await streamTask; 8 return responseText; 9 } 10 catch (System.Net.Http.HttpRequestException e) when (e.Message.Contains("301")) 11 { 12 await logError("Recovered from redirect", e); 13 return "Site Moved"; 14 } 15 finally 16 { 17 await logMethodExit();
18 } 19 }
这个功能并无什么新意,其实之前就支持集合/字典 初始化器了,如:
1 var list = new List<string>() 2 { 3 "Mike", 4 "Jim" 5 }; 6 7 var dic = new Dictionary<int, string>() 8 { 9 { 20, "Mike" }, 10 { 30, "Jim" } 11 };
在C# 6中只是字典初始化器支持了新的写法,如:
1 var dic = new Dictionary<int, string>() 2 { 3 [20] = "Mike", 4 [30] = "Jim" 5 };
总结:暂无发现特殊的用法。
这算不上是新语法,由于仅仅是编译器的改进,之因此一提是想让你们知道有这么一回事。之前的编译器是识别不了 Task.Run(Func<Task>())
的,以下:
1 static Task DoThings() 2 { 3 return Task.FromResult(0); 4 } 5 6 Task.Run(DoThings); // 此处省略方法代码...
上述代码在老版本编译器下是编译不经过的,而在新版本编译器是能编译经过的。
备注:值得一提的是新版本编译器也只是识别了Task.Run(Func<Task>()),Task.Run(Action) 仍是识别不了,总的来讲此功能对咱们用处不大,
还不如乖乖的写回Lambda表达式。
因为篇幅所限,C# 7 新增的功能就放在下篇介绍......