0.3 C# 6的新特性
在C# 6中有一个新的C#编译器。它完成源代码的清理。现在自定义程序也可以使用编译器管道的特性,并使用Visual Studio的许多特性。
这个新的C#编译器平台允许用许多新特性改进C#。虽然这些特性都没有LINQ或async关键字的影响大,但许多改进都提高了开发人员的效率。C# 6有哪些变化?
0.3.1 静态的using声明
静态的using声明允许调用静态方法时不使用类名。
C# 5 using System; // etc. Console.WriteLine("Hello, World! "); C# 6 using static System.Console; // etc. WriteLine("Hello, World"); using static关键字参见第2章。
0.3.2 表达式体方法
表达式体方法只包括一个可以用lambda语法编写的语句:
C# 5 public bool IsSquare(Rectangle rect) { return rect.Height == rect.Width; } C# 6 public bool IsSquare(Rectangle rect) => rect.Height == rect.Width;
表达式体方法参见第3章。
0.3.3 表达式体属性
与表达式体方法类似,只有get存取器的单行属性可以用lambda语法编写:
C# 5 public string FullName { get { return FirstName + " " + LastName; } } C# 6 public string FullName => FirstName + " " + LastName;
表达式体属性参见第3章。
0.3.4 自动实现的属性初始化器
自动实现的属性可以用属性初始化器来初始化:
C# 5 public class Person { public Person() { Age = 24; } public int Age {get; set; } } C# 6 public class Person { public int Age {get; set; } = 42; }
自动实现的属性初始化器参见第3章。
0.3.5 只读的自动属性
为了实现只读属性,C# 5需要使用完整的属性语法;而在C# 6中,可以使用自动实现的属性:
C# 5 private readonly int _bookId; public BookId { get { return _bookId; } } C# 6 public BookId {get; }
只读的自动属性参见第3章。
0.3.6 nameof运算符
使用新的nameof运算符,可以访问字段名、属性名、方法名或类型名。这样,在重构时,就不会遗漏名称的改变:
C# 5 public void Method(object o) { if (o == null) throw new ArgumentNullException("o"); C# 6 public void Method(object o) { if (o == null) throw new ArgumentNullException(nameof(o));
nameof运算符参见第8章。
0.3.7 空值传播运算符
空值传播运算符简化了空值的检查:
C# 5 int? age = p == null ? null : p.Age; C# 6 int? age = p? .Age;
新语法也有触发事件的优点:
C#5 var handler = Event; if (handler ! = null) { handler(source, e); } C# 6 handler? .Invoke(source, e);
空值传播运算符参见第8章。
0.3.8 字符串插值
字符串插值删除了对string.Format的调用,它不在字符串中使用编号的格式占位符,占位符可以包含表达式:
C# 5 public override ToString() { return string.Format("{0}, {1}", Title, Publisher); } C# 6 public override ToString() => $"{Title} {Publisher}";
与C# 5语法相比,C# 6示例的代码减少了许多,不仅因为它使用了字符串插值,还使用了表达式体方法。
字符串插值还可以使用字符串格式,把它分配给FormattableString时会获得特殊的功能。字符串插值参见第10章。
0.3.9 字典初始化器
字典现在可以用字典初始化器来初始化,类似于集合初始化器。
C# 5 var dict = new Dictionary<int, string>(); dict.Add(3, "three"); dict.Add(7, "seven"); C# 6 var dict = new Dictionary<int, string>() { [3] = "three", [7] = "seven" };
字典初始化器参见第11章。
0.3.10 异常过滤器
异常过滤器允许在捕获异常之前过滤它们。
C# 5 try { //etc. } catch (MyException ex) { if (ex.ErrorCode ! = 405) throw; // etc. } C# 6 try { //etc. } catch (MyException ex) when (ex.ErrorCode == 405) { // etc. }
新语法的一大优势是,它不仅减少了代码的长度,而且没有改变堆栈跟踪——在C# 5中会改变堆栈跟踪。异常过滤器参见第14章。
0.3.11 Catch中的await
await现在可以在catch子句中使用。C# 5需要一种变通方法:
C# 5 bool hasError = false; string errorMessage = null; try { //etc. } catch (MyException ex) { hasError = true; errorMessage = ex.Message; } if (hasError) { await new MessageDialog().ShowAsync(errorMessage); } C# 6 try { //etc. } catch (MyException ex) { await new MessageDialog().ShowAsync(ex.Message); }
这个功能不需要增强的C#语法,现在就能工作。这个增强需要微软公司大量的投资才能实现,但是否使用这个平台真的没有关系。对用户来说,这意味着需要更少的代码——仅仅是比较两个版本。
注意:新的C# 6语言特性参见后面的章节,本书的所有章节都使用了新的C#语法。