Preview what's new in C#10

Preview what's new in C#10

Learning never stops

最后更新 6/1/2021 10:19 PM
Ken Bonny&Rwing
预计阅读 6 分钟
分类
.NET
标签
.NET C#

本周早些时候(译注:原文发表于 5 月 1 日),我关注了 Mads TorgersenDotNet SouthWest 大会上的演讲,他是微软的 C# 语言的首席设计师。他概述了 C# 10 即将包含的很酷的一些新东西。让我们来快速浏览一下。

With a small disclaimer, most of these changes have been basically completed. But since it is still under active development, I can't guarantee that everything will be completely true when C#10 is released.

struct record

他谈到的第一件事是,目前 record 的实现是使用一个 class 作为基础对象的。现在还会有一个 record struct 的变体可用,所以基础类型可以是一个值类型。区别在于,普通的 record 在函数之间传递的是引用,而 record struct 是其值的拷贝。 record struct 也会支持 with 运算符。

It also allows operators to be added to record, and both record types are okay.

record Person(string Name, string Email)
{
  public static Person operator +(Person first, Person second)
  {
    // logic goes here
  }
}

required

One of the goals of the C#team's focus is to make it easier to initialize objects. This is why you can add required flags to properties of class, struct, record, or struct record. It makes these attributes mandatory. This can be done through a constructor or through object initialization. The definitions of the two classes below are equivalent. If you add the required keyword, you cannot instantiate Person without setting the Name attribute. The compiler throws an error and cannot compile.

class Person
{
  public required string Name { get; set; }
  public DateTime DateOfBirth { get; set; }
}
class Person
{
  public Person(string name) => Name = name;

  public string Name { get; set; }
  public DateTime DateOfBirth { get; set; }
}

field

To further improve properties, it will allow you to completely get rid of backing fields. The new keyword field will provide access to these fields. You can use both setter and init only attributes.

class Person
{
  public string Name { get; init => field = value.Trim(); }
  public DateTime DateOfBirth { get; set => field = value.Date; }
}

with

在下一个版本中还会有一些有趣的小改进。其实中一个是匿名类型也将支持 with 运算符。

var foo = new
{
  Name = "Foo",
  Email = "foo@mail.com"
};
var bar = foo with {Name = "Bar"};

namespace

现在可以创建一个带有命名空间导入的文件,然后在任何地方都可以使用这个导入。例如,如果有一个很常用的命名空间,几乎在每个文件中都使用例如 Microsoft.Extensions.Logging.ILogger ,那么就可以在任何.cs 文件(我建议在 Program.cs 或专门的 Imports.cs )中添加一行 global using Microsoft.Extensions.Logging.ILogger,之后这个命名空间将可以在整个项目中使用。注意,这不适用于整个解决方案! 没有人能够预测哪些地方需要导入,所以它们被分组到每个项目中。

// 译注:原文并没有提供代码示例,为了更好方便大家理解私自添加了一个演示
// Program.cs 文件
global using System;

// Sample.cs 文件
// 可以不用再using System;
Console.WriteLine("foo");

Later, there will also be an optimization for namespaces. Namespaces now require curly braces to wrap the code, which means that all code must be indented at least once. To save tabs (or four spaces) and screen space, adding a namespace anywhere in the file will make all code belong to that namespace. Studies have shown that in the vast majority of cases, all code in a file belongs to the same namespace. After using this solution, the file size decreases, which may not be obvious to a solution (even if it contains thousands of files), but on GitHub/GitLab/BitBucket/... On the scale of this, I think it will save them some space. If someone still wants to include multiple namespaces in a file, the option to use braces is still available.

// 传统的方式 LegacyNamespace.cs
namespace LegacyNamespace
{
  class Foo
  {
    // legacy code goes here
  }
}

// 简化的方式 SimplifiedNamespace.cs
namespace SimplifiedNamespace;
class Bar
{
  // awesome code goes here
}

lambda

There will also be some cool updates to lambda statements. The compiler will provide better support for inferring lambda signatures and can add features. Words can explicitly specify the return type to help the compiler understand lambda.

var f = Console.WriteLine;
var f = x => x; // 推断返回类型
var f = (string x) => x; // 推断签名
var f = [NotNull] x => x; // 添加特性
var f = [NotNull] (int x) => x;
var f = [return: NotNull] static x => x; // 添加特性
var f = T () => default; // 显式返回类型
var f = ref int (ref int x) => ref x; // 使用 ref
var f = int (x) => x; // 显式指定隐式输入的返回类型
var f = static void (_) => Console.Write("Help");

Thanks to Schooley for presenting an example of a less confusing feature

interface

Finally, it will be possible to specify static methods and properties on the interface. I know this will be a controversial topic, like adding a default implementation to an interface. I don't like it. However, this can be very interesting. Imagine that you can specify default values for an interface or specify a creation method.

interface IFoo
{
  static IFoo Empty { get; }
  static operator +(IFoo first, IFoo second);
}
class Foo : IFoo
{
  public static IFoo Empty => new Foo();
  public static operator +(IFoo first, IFoo second) => /* do calculation here */;
}

就个人而言,我喜欢这些变化。我最喜欢的是对命名空间的改变和对接口的改进。总之,未来是光明的 C# 的。嗯嗯... (译注:这里作者玩了一个梗,原文 the future is seeing sharp,see sharp 发音类似 C# )

Thank you, everyone, goodbye.

Keep Exploring

延伸阅读

更多文章
同分类 / 同标签 4/22/2026

Support for. NET by operating system versions (250707 update)

Use virtual machines and test machines to test the support of each version of the operating system for. NET. After installing the operating system, it is passed by measuring the corresponding running time of the installation and being able to run the Stardust Agent.

继续阅读
同分类 / 同标签 2/7/2026

Summary of experience in using AOT

From the very beginning of project creation, you should develop a good habit of conducting AOT release testing in a timely manner whenever new features are added or newer syntax is used.

继续阅读