C# 7.0 添加和增强的功能【基础篇】( 三 )

GetText 的方法是私有的:
private static string GetText(string path, string filename){var reader = File.OpenText($"{AppendPathSeparator(path)}{filename}");var text = reader.ReadToEnd();return text;string AppendPathSeparator(string filepath){return filepath.EndsWith(@"\") ? filepath : filepath + @"\";}}本地函数的一个实用功能是可以允许立即显示异常 。
对于方法迭代器,仅在枚举返回的序列时才显示异常,而非在检索迭代器时 。
对于异步方法 , 在等待返回的任务时,将观察到异步方法中引发的任何异常 。
本地函数和lambda表达式是十分相似的,但两者中选用一种的时机和条件其实是存在差别 。
// 本地函数public static int LocalFunctionFactorial(int n){return nthFactorial(n);int nthFactorial(int number) => number < 2? 1: number * nthFactorial(number - 1);}// Lambda 表达式public static int LambdaFactorial(int n){Func<int, int> nthFactorial = default(Func<int, int>);nthFactorial = number => number < 2? 1: number * nthFactorial(number - 1);return nthFactorial(n);}本地函数的命名方式与方法相同 。Lambda表达式是一种匿名方法,需要分配给 delegate 类型的变量,通常是 Action 或 Func 类型 。声明本地函数时,此过程类似于编写普通方法;声明一个返回类型和一个函数签名 。
Lambda表达式在声明时转换为委托 。本地函数更加灵活,可以像传统方法一样编写,也可以作为委托编写 。只有在用作委托时,本地函数才转换为委托 。如果声明了本地函数 , 但只是通过像调用方法一样调用该函数来引用该函数,它将不会转换成委托 。
本地函数可以避免Lambda表达式始终需要的堆分配 。如果本地函数永远不会转换为委托,并且本地函数捕获的变量都不会被其他转换为委托的Lambda或本地函数捕获 , 则编译器可以避免堆分配 。
yield 关键字的用法:
// 可将本地函数作为迭代器实现,使用 yield return 语法生成一系列值public IEnumerable<string> SequenceToLowercase(IEnumerable<string> input){if (!input.Any())throw new ArgumentException("There are no items to convert to lowercase.");return LowercaseIterator();IEnumerable<string> LowercaseIterator(){foreach (var output in input.Select(item => item.ToLower()))yield return output;}}虽然本地函数对 lambda 表达式可能有点冗余,但实际上它们的目的和用法都不一样 。如果想要编写仅从上下文或其他方法中调用的函数,则使用本地函数更高效 。
七、扩展 Expression bodied 成员在C# 6.0中已经新增了表达式主体定义,而在当前版本中进行了扩展 。扩展的内容包括下面几点 。
可以使用表达式主体定义来实现属性 get 和 set 访问器 。
public class Location{private string locationName;public Location(string name) => Name = name;public string Name{get => locationName;set => locationName = value;}}构造函数的表达式主体定义通常包含单个赋值表达式或一个方法调用 , 该方法调用可处理构造函数的参数,也可初始化实例状态 。
// 其构造函数具有一个名为“name”的字符串参数,表达式主体定义向 Name 属性分配参数public class Location{private string locationName;public Location(string name) => Name = name;public string Name{get => locationName;set => locationName = value;}}终结器的表达式主体定义通常包含清理语句,例如释放非托管资源的语句 。
// 定义一个终结器,该终结器使用表达式主体定义来指示已调用该终结器public class Destroyer{public override string ToString() => GetType().Name;~Destroyer() => Console.WriteLine($"The {ToString()} finalizer is executing.");}索引器与使用属性一样,如果 get 访问器包含返回值的单个表达式或 set 访问器执行简单的赋值 , 则索引器 get 和 set 访问器包含表达式主体定义 。
using System;using System.Collections.Generic;// 其中包含一个内部 String 数组,该数组包含大量体育运动的名称// 索引器的 get 和 set 访问器都以表达式主体定义的形式实现public class Sports{private string[] types = { "Baseball", "Basketball", "Football","Hockey", "Soccer", "Tennis","Volleyball" };public string this[int i]{get => types[i];set => types[i] = value;}}八、ref 局部变量在变量类型之前添加 ref

推荐阅读