

.NET6系列:C#10新功能预览
source link: https://www.cnblogs.com/SavionZhang/p/14839771.html
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.

2021年4月19日微软发布公告称将于今年夏季发布首款64位的 Visual Studio 2022,2021年5月20日又发布了 Visual Studio 2022 线路图,进一步提升开发生产力。与 Visual Studio 黄金搭档的 C# 语言一直都是秒天秒地秒空气的存在。C#10,今天它来了。
小小的免责声明,这些变化大多数几乎都完成了。由于它仍在积极开发中,我不能保证一切都与 C# 10 发布时完全一样。
他首先谈到的是 record 的当前实现是使用类(reference type)作为基对象的。C#10中即将提供一个 record struct,它的基础类型可以是值类型。不同之处在于,常规 record 将通过引用从一个函数传递到另一个函数,而 record struct 将通过其值进行复制。record struct 也将支持 with 表达式。
同时,还可以向 record 中添加运算符。这两种 record 类型都可以使用。
record Person(string Name, string Email) { public static Person operator +(Person first, Person second) { // TODO 业务逻辑 } }
C# 团队关注的目标之一是使对象的初始化更容易。这就是为什么可以根据需要对 class
,struct
,record
或 record struct
添加 required 特性标记
。它强制要求这些属性必须赋值。这可以通过构造函数来完成,或者可以通过对象初始化来完成。下面的两个类定义是等效的。如果用required
关键字写的话,不设置Name
属性就不能实例化Person 。编译器会抛出错误并且无法编译。
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; } }
为了进一步改善属性(properties),可以完全摆脱 backing field。新的关键字 field 将提供对所述支持字段的访问。它对 setter 和 init only 属性都可以使用。
class Person { public string Name { get; init => field = value.Trim(); } public DateTime DateOfBirth { get; set => field = value.Date; } }
在下一个版本中也会有一些漂亮的小改进。其中之一就是 with
操作符也将支持匿名类型。
var foo = new { Name = "Foo", Email = "[email protected]" }; var bar = foo with {Name = "Bar"};
现在可以创建一个文件,其中的命名空间导入可以在任何地方使用。例如,如果在几乎每个文件中都使用了一个常用的名称空间,例如Microsoft.Extensions.Logging.ILogger,那么就可以将全局命名空间 using Microsoft.Extensions.Logging.ILogger 添加到任何.cs文件中(我建议使用Program.cs或专用Imports.cs),整个项目中都可以使用 logger 接口。但是,该方法不适用于整个解决方案(solution)。因为没有人能预测哪些地方需要导入,所以它们是按项目分组到每个项目(project)中。
随后,还会对 namespace
进行优化。现在 namespace
需要花括号 {} 来对代码进行分组,这意味着所有代码至少要缩进一次。为了节省 tab(或四个空格)和屏幕空间,在文件中的任何位置添加一个 namespace,将使所有代码都属于该namespace
。有相关研究表明绝大多数情况下,一个文件中的几乎所有代码都属于同一个 namespace
。使用该方案优化后,文件大小会减小,这对于一个解决方案(即使它包含数千个文件)来说可能并不重要,但在 GitHub/GitLab/BitBucket/...的规模上,我认为这将为他们节省一些空间。如果有人仍想在一个文件中包含多个命名空间,则仍然可以选择使用大括号。
// 传统方式 LegacyNamespace.cs namespace LegacyNamespace { class Foo { // ToDo 业务逻辑 } } // 简化后的方式 SimplifiedNamespace.cs namespace SimplifiedNamespace; class Bar { // ToDo 业务逻辑 }
lambda 语句也有一些很酷的更新。编译器将更好地支持推断 lambda 签名,并且还可以添加属性。可以指定显式返回类型以帮助编译器理解 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; // 在 struct 上使用 ref 关键字 var f = int (x) => x; // 显式指定隐式输入的返回类型 var f = static void (_) => Console.Write("Help");
最后,可以在接口上指定静态方法和属性。我知道这将是一个有争议的话题,就像向接口添加默认实现一样。虽然我不喜欢它,然而这可能非常有趣。想象一下,您可以指定接口的默认值或指定创建方法。
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) => /* 在此做逻辑计算 */; }
就个人而言,我喜欢这些变化。尤其是 namespace 和 interface 的
变化和改进。不管怎样,C#的未来是光明的。
参考文献:
- https://kenbonny.net/introducing-csharp-10
Recommend
About Joyk
Aggregate valuable and interesting links.
Joyk means Joy of geeK