当前位置:首页 > 通信资讯 > 正文

dotnet4.0(dotnet4.5)

dotnet4.0(dotnet4.5)

C# 9,对应的是 Dotnet 5.0。

这个出来也有些日子了,不过好像群里很多人还是没往这个版本走。

我这边现在是全线已经转向了 5.0,还是我经常说的那个原因:爽。Dotnet 的每一次升级,都有一些让人惊喜的特性,让代码更合理,更节省时间。

1. 基础语言方面

语言方面,最主要的特性,是 Record。这是 C# 9 出来的一个新数据类型。没错,Record 是一个数据类型。

这个 Record 提供了一些很爽的表示数据的内置功能,以至于使用的时候,感觉它更像一个类。

按微软的说法,Record 的目的,是提供一个更小更简单的类型来表示不可变数据。不过在使用中,我更喜欢用它来做数据传输。

定义一个 Record

定义一个 Record 有几种方式。最简单的形式是:

  1. publicrecordUser(stringname,intage);

第一次看这个东西,会有点奇怪,有没有?长得有点像方法,可就没内容。

嗯,这确实是 Record 的一个声明定义,定义了一个对象 user,这个对象 user 具有 name 和 age 两个属性。可以通过以下方式来访问:

  1. varsome_user=newUser("WangPlus",35);
  2. Console.WriteLine(some_user.name);//输出WangPlus
  3. Console.WriteLine(some_user.age);//输出35

确实跟类有点像。

再来看看另一种定义方式,会更像一个类:

  1. publicrecordUser
  2. {
  3. publicstringname{get;set;}
  4. publicintage{get;set;}
  5. }

给 Record 赋值

既然长得像类,我们可以像类一样去赋值:

  1. varsome_user=newUser{name="WangPlus",age=35};

还可以用位置语法,近一步简化:

  1. Usersome_user=new("WangPlus",35);

注意这个位置语法,其实就是按位置匹配字段的意思。赋值时的值,会自动去找对应位置的属性来匹配和校验。

而且,对于第一种简单定义:

  1. publicrecordUser(stringname,intage);

赋值语句实际编译时,上面字段中的 set 会被替换为 init,即:

  1. publicrecordUser
  2. {
  3. publicstringname{get;init;}
  4. publicintage{get;init;}
  5. }

这意味着属性在初始化后无法改变,会变成只读属性。

相等判断

Record 对于相等的定义是内部的属性相等。也就是说,判断两个 Record 是否相等时,将检查每个属性的值,而不是对象的引用地址。

看例子:

  1. Usersome_user1=new("WangPlus",35);
  2. Usersome_user2=new("WangPlus",35);
  3. Console.WriteLine(some_user1==some_user2);//true
  4. Console.WriteLine(ReferenceEquals(some_user1,some_user2));//false

例子中,some_user1 和 some_user2 属性相同,所以他们是相等的,尽管是两个不同的引用。

不一样的 ToString()

Record 的 ToString 是一个内置方法,跟别的对象的 ToString 有很大区别。它会把 Record 的定义、属性和值全部输出。上面的例子,输出的内容将会是:

  1. User{name=WangPlus,age=35}

注意:如果某个 Record 的属性是引用类型,ToString 将会输出这个类型的名称。

Record 值的传递

这个内容延续到了 C# 10,相关内容我在 「Dotnet 6.0,你值得拥有」里有详细的描述,可以去看看。

这里简单说一下,就是使用 With:

  1. Usersome_user=new("WangPlus",35);
  2. Userother_user=some_userwith{name="WangPlus1"};

定义 Init 属性

C# 9 里,新增了一个对于属性定义的 init 关键字。这个关键字可以用在 Struct、Class、Record 中,表示属性仅在初始化时可以进行设置。

例如:

  1. publicrecordUser
  2. {
  3. publicstringname{get;set;}
  4. publicintage{get;init;}
  5. }

这里,age 属性被定义为 init。赋值还是一样的:

  1. Usersome_user=new("WangPlus",35);

当改变值时,例如:

  1. some_user.name="WangPlus1";

这个是有效的,但是:

  1. some_user.age=36;

这句话会报错,因为在上面定义中,age 被定义为 init,即只有初始化时可以赋值。

以上是 C# 9 中增加的最重要的一个内容:Record 类型。

2. API 方面

API 方面,主要是三个特性。

1). 顶级程序

这算是大家盼了很久的一个特性。

早期,一个程序的开始,会是这个样子:

  1. usingSystem;
  2. namespaceDemo
  3. {
  4. staticclassProgram
  5. {
  6. staticvoidMain(string[]args)
  7. {
  8. Console.WriteLine("HelloWorld!");
  9. }
  10. }
  11. }

现在有了顶级程序的规则,这一大段,可以直接简化为:

  1. System.Console.WriteLine("HelloWorld");

就OK了。Program 啦,Main 啦,统统都可以不写了。

对于 WebAPI 应用也一样:

  1. usingMicrosoft.AspNetCore.Hosting;
  2. usingMicrosoft.Extensions.Hosting;
  3. namespaceDemo
  4. {
  5. publicclassProgram
  6. {
  7. publicstaticvoidMain(string[]args)
  8. {
  9. CreateHostBuilder(args).Build().Run();
  10. }
  11. publicstaticIHostBuilderCreateHostBuilder(string[]args)=>
  12. Host.CreateDefaultBuilder(args)
  13. .ConfigureWebHostDefaults(webBuilder=>
  14. {
  15. webBuilder.UseStartup<Startup>();
  16. });
  17. }
  18. }

这是一个标准的 WebAPI 应用的开始。现在,也可以简化成:

  1. usingMicrosoft.AspNetCore.Hosting;
  2. usingMicrosoft.Extensions.Hosting;
  3. CreateHostBuilder(args).Build().Run();
  4. IHostBuilderCreateHostBuilder(string[]args)=>
  5. Host.CreateDefaultBuilder(args)
  6. .ConfigureWebHostDefaults(webBuilder=>
  7. {
  8. webBuilder.UseStartup<Startup>();
  9. });

这样的代码其实更简洁,而且可以直观的说明程序的意图。如果你也经常写 Python,那你会很喜欢这个特性。

2). 新的匹配模式

C# 9 里,终于加入了大家期盼已久的新的匹配模式。主要有两类:

第一类:逻辑匹配

这个主要是加入了 And、Or 和 Not。

以前,我们会用到这样的判断:

  1. if(input==null){}

有时候,我们也会写成:

  1. if(inputisnull){}

但是,判断不等于时,我们只有一种方式,就是:

  1. if(input!=null){}

现在,我们有了更可读的写法:

  1. if(intisnotnull){}

看起来可读性就很高了。

第二类:关系匹配

这个特性,涉及的是 <、>、<=、>=,最主要的是改变了 Switch。

以前,使用 Switch 时,Case 必须是可枚举的值,看例子:

  1. switch(input)
  2. {
  3. case1:
  4. break;
  5. case2:
  6. break;
  7. default:
  8. break;
  9. }

现在,这里面加入了范围判断,可以这么写:

  1. switch(input)
  2. {
  3. case<5:
  4. break;
  5. case>=5and<=9:
  6. break;
  7. default:
  8. break;
  9. }

看到没?更多的逻辑可以在 Switch 里实现,而不用一大篇 if…else 了。

3). 类型省略

这个特性涉及到代码的方方面面,主要的目的,是为了减少代码的输入量。

看个例子,以前我们定义一个字段,通常是这样:

  1. publicListusers=newList();

现在,我们可以直接省略后面的部分,编译器会很聪明的知道我们想 New 什么:

  1. publicList<User>users=new();

方法也是一样。假设我们有一个方法:

  1. publicstaticclassUsers
  2. {
  3. publicUsercopyUser(Usersource){}
  4. }

以前调用时,我们需要先给个变量,再调用方法:

  1. Usersource_user=newUser();
  2. Users.copyUser(source_user);

现在,我们可以在方法中直接 New:

  1. Users.copyUser(new());

当然,这个特性也结合了上面 Record 的特性。

因此,我们还可以这么写:

  1. Users.copyUser(new(){name="WangPlus"});

嗯,语庋的改变需要一点时间来适应,但从长远来看,依然是一种进步,会让代码更方便写和读。同时,这个特性,和 Var 会变成编程的两个面,哪个更好用,看自己的习惯了。

3. 总结

总的来说,Dotnet 5.0 的变化还是有很多惊喜的。上面写的,只是我们能比较容易感受到的部分,感受不到的部分,比方编译的合理性、性能的优化,GC的回收,做得都相当优秀。

早转 5.0 早好,对吧?

原文链接:https://mp.weixin.qq.com/s/RfYDOR407DUZp6SxE6BzIw

如果您对该产品感兴趣,请填写办理(客服微信:xiaoxiongyidong)

为您推荐:

发表评论

◎欢迎参与讨论,请在这里发表您的看法、交流您的观点。