C#7.0中有哪些新特性?(3)

Note:元组依赖于一组基本类型,却不包括在 Preview 4 中。为了使该特性工作,你可以通过 NuGet 获取它们:
•右键单击 Solution Explorer 中的项目,然后选择“管理的NuGet包......”
•选择“Browse”选项卡,选中“Include prerelease”,选择“nuget.org”作为“Package source”
•搜索“System.ValueTuple”并安装它。

解构

消耗元组的另一种方法是将解构它们。一个解构声明是一个将元组(或其他值)分割成部分并单独分配到新变量的语法:

(string first, string middle, string last) = LookupName(id1); // deconstructing declaration
WriteLine($"found {first} {last}.");

在解构声明中,您可以使用 var 来声明单独的变量:

(var first, var middle, var last) = LookupName(id1); // var inside

或者将一个单独的 var 作为一个缩写放入圆括号外面:

var (first, middle, last) = LookupName(id1); // var outside

你也可以使用解构任务来解构成��有的变量

(first, middle, last) = LookupName(id2); // deconstructing assignment

解构不只是应用于元组。任何的类型都可以被解构,只要它具有(实例或扩展)的解构方法:

public void Deconstruct(out T1 x1, ..., out Tn xn) { ... }

输出参数构成了解构结果中的值。

(为什么它使用了参数,而不是返回一个元组?这是为了让你针对不同的值拥有多个重载)。

class Point
{
    public int X { get; }
    public int Y { get; }
 
    public Point(int x, int y) { X = x; Y = y; }
    public void Deconstruct(out int x, out int y) { x = X; y = Y; }
}
(var myX, var myY) = GetPoint(); // calls Deconstruct(out myX, out myY);

这是一种常见的模式,以一种对称的方式包含了构建和解构。

对于输出变量,我们计划在解构中加入通配符,来化简你不关心的变量:

(var myX, *) = GetPoint(); // I only care about myX

Note:通配符是否会出现在C#7.0中,这仍是未知数。

局部函数

有时候,一个辅助函数可以在一个独立函数内部起作用。现在,你可以以一个局部函数的方式在其它函数内部声明这样的函数:

public int Fibonacci(int x)
{
    if (x < 0) throw new ArgumentException("Less negativity please!", nameof(x));
    return Fib(x).current;
 
    (int current, int previous) Fib(int i)
    {
        if (i == 0) return (1, 0);
        var (p, pp) = Fib(i - 1);
        return (p + pp, p);
    }
}

闭合范围内的参数和局部变量在局部函数的内部是可用的,就如同它们在 lambda 表达式中一样。

举一个例子,迭代的方法实现通常需要一个非迭代的封装方法,以便在调用时检查实参。(迭代器本身不启动运行,直到 MoveNext 被调用)。局部函数非常适合这样的场景:

public IEnumerable<T> Filter<T>(IEnumerable<T> source, Func<T, bool> filter)
{
    if (source == null) throw new ArgumentNullException(nameof(source));
    if (filter == null) throw new ArgumentNullException(nameof(filter));
 
    return Iterator();
 
    IEnumerable<T> Iterator()
    {
        foreach (var element in source)
        {
            if (filter(element)) { yield return element; }
        }
    }
}

如果迭代器有一个私有方法传递给过滤器,那么当其它成员意外的使用迭代器时,迭代器也变得可用(即使没有参数检查)。此外,还会采取相同的实参作为过滤器,以便替换范围内的参数。

注意:在 Preview 4,局部函数在调用之前,必须被声明。这个限制将会被松开,以便使得局部函数从定义分配中读取时,能够被调用。

文字改进

C#7.0 允许 _ 出现,作为数字分隔号:
var d = 123_456;
var x = 0xAB_CD_EF;

你可以将 _ 放入任意的数字之间,以提高可读性,它们对值没有影响。

此外,C#7.0 引入了二进制文字,这样你就可以指定二进制模式而不用去了解十六进制。
var b = 0b1010_1011_1100_1101_1110_1111;

引用返回和局部引用

就像在 C# 中通过引用来传递参数(使用引用修改器),你现在也可以通过引用来返回参数,同样也可以以局部变量的方式存储参数。

public ref int Find(int number, int[] numbers)
{
    for (int i = 0; i < numbers.Length; i++)
    {
        if (numbers[i] == number)
        {
            return ref numbers[i]; // return the storage location, not the value
        }
    }
    throw new IndexOutOfRangeException($"{nameof(number)} not found");
}
 
int[] array = { 1, 15, -39, 0, 7, 14, -12 };
ref int place = ref Find(7, array); // aliases 7's place in the array
place = 9; // replaces 7 with 9 in the array
WriteLine(array[4]); // prints 9

内容版权声明:除非注明,否则皆为本站原创文章。

转载注明出处:https://www.heiqu.com/7d7cfaca8e66b848bb4b9bf1117e47b0.html