C#高级编程(第10版) C# 6 & .NET Core 1.0 (.NET开发经典名著)
上QQ阅读APP看书,第一时间看更新

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#语法。