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

六、本地函数本地函数是一种嵌套在另一成员中的类型的私有方法 。仅能从其包含成员中调用它们 。
【C# 7.0 添加和增强的功能【基础篇】】可以声明和调用本地函数的地方:
??方法(尤其是迭代器方法和异步方法)、构造函数、属性访问器、事件访问器、匿名方法、Lambda 表达式、终结器、其他本地函数等 。
以下示例定义了一个名为 AppendPathSeparator 的本地函数,该函数对于名为 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;}}构造函数的表达式主体定义通常包含单个赋值表达式或一个方法调用,该方法调用可处理构造函数的参数,也可初始化实例状态 。

经验总结扩展阅读