代码改变世界

[翻译]欢迎来到 C# 7.1

2017-11-01 16:20  Rwing  阅读(2230)  评论(3编辑  收藏  举报

[翻译]欢迎来到 C# 7.1

原文: Welcome to C# 7.1

在 C# 中,我们一直倾向于主要版本:捆绑了很多功能,并且不太频繁地发布。当我们谈到 C#6.0时,我们甚至还经常忽略掉后面的“.0”!

在 C#7.0 这一“波”中,我们正在尝试新的东西。像 Visual Studio 这样频繁的升级节奏,为什么 C# 不能也频繁的升级呢,这已经不存在技术原因了。所以这一次,我们正在拥抱“点发布”的概念; C#的次要版本会以更短的间隔更新,并且提供有用且较小的语言功能。这意味着您不必等待很长时间才能获得高级特性,而且还可以更容易地将C#版本与相关功能的发布相一致,例如.NET。

当然,对于团队来说,将语言升级到新版本“一直以来”都是件麻烦事,对于个人来说还好。 Visual Studio 2017 允许您决定是否切换到最新版本,或使用主要的版本。你可以选择你的喜好。

第一个“点发布”

在2017年8月,我们发布了 C# 的第一个“点发布”版。它被称为 C#7.1,其主要目的是为我们的“点发布”积累经验,并且保证没有太多的依赖以使问题复杂化。

因此,C#7.1是一个很小的版本,只有少数(但精心挑选的)新语言特性; 我们认为它们是有用的,并且一定在某些场景下有用。 Visual Studio 2017 Update 15.3 开始支持。

现在我们来看一下!这是一个涵盖了三个 C#7.1 新特性的程序,加上最近 C#7.0 的一些特性,旨在使其有趣。

using System.Linq;
using System.Threading;
using System.Threading.Tasks;

using static System.Console;

class Program
{
    static async Task Main(string[] args)
    {
        var results = Enumerable.Range(1, 40)
            .Select(input => (input, task: FibonacciAsync(input)))
            .ToArray();

        foreach (var tuple in results)
        {
            WriteLine($"Fib {tuple.input} = {await tuple.task}");
        }
    }

    private static Task<int> FibonacciAsync(int n, CancellationToken token = default)
    {
        return Task.Run(() => Fib(n).curr, token);

        (int curr, int prev) Fib(int i)
        {
            if (i is 0) return (1, 0);
            var (c, p) = Fib(i - 1);
            return (c + p, c);
        }
    }
}

它在线程池中并行计算前40个斐波纳契数,并按顺序打印出来。

我们来看看这里使用的每个新的 C#7.1 特性。要全面的了解 C#7.1 中新特性,请查看文档

Main 方法可以 Async

现在 Main 入口点方法可以返回 Task 或 Task。当它执行时,执行将等待返回的任务完成,然后关闭程序。

当然,常用的方法就是使 Main 方法异步,你可以这样做:

static async Task Main(string[] args)

这会让你可以直接在 Main 方法里 await, 这在以前是不行的。

WriteLine($"Fib {tuple.input} = {await tuple.task}");

以前的话,想达到这个效果是很麻烦:首先创建一个 async 的辅助方法,MainAsync,写上所有逻辑,然后写个怪异的 Main 方法:

static void Main(string[] args) => MainAsync().GetAwaiter().GetResult();

现在你可以直接让你的 Main 方法 async,编译器会帮你重写它。

推断元组元素的名称

在这个lambda表达式里面的查询:

input => (input, task: FibonacciAsync(input))

您注意到,我们创建一个元组,但只为第二个元素提供一个名称, task。然后我们可以直接这么写

WriteLine($"Fib {tuple.input} = {await tuple.task}");

用名称tuple.input来访问第一个元素。这是因为当您创建一个有名称的表达式元组时,如上面的lambda表达式中的输入,我们将自动给予相应的元组元素一个名称。

Default literals 默认常值

如果默认表达式有预期类型,那么现在可以省略对类型的说明,就像在 FibonacciAsync 方法的签名中的 CancellationToken 一样:

private static Task<int> FibonacciAsync(int n, CancellationToken token = default)

这避免了繁琐的类型名称重复,或者当已经由上下文给出时,输出长的类型名称。

What’s next?

我们已经在开发 C#7.2,以及下一个主要版本的特性。 如果你好奇,你可以跟随并参加C#语言设计GitHub repo:github.com/dotnet/csharplang