C#新语法

NET6新特性以及C#新语法

1.顶级语句(C#9.0)

(1):直接在C#文件中直接编写入口方法的代码,不用类,不用Main。经典写法仍然支持,反编译可以查看到,编译器依旧为我们生成了一个<Main>$与Main差不多的方法。实际是语法糖而已

(2):同一个项目中只能有一个文件具有顶级语句。(由于本质是有Main()函数的,所以只能有一个)

(3):顶级语句中可以直接使用await语法,也可以声明函数。(以前写的写法是如果需要用异步的方法)

 //反编译如下代码
 [CompilerGenerated]
 internal class Program
 {
  private static void <Main>$(string[] args)
  {
  using (TestDbContext ctx = new TestDbContext())
  {
  ctx.Books.Where("Price > 0 and Price < 66").Select("new (Title,AuthorName)").ToDynamicArray();
  }
  }
 }
 //之前如果需要调用异步方法 Main方法需要修改成这样 顶级语句不需要
 static async Task Main(string[] args)
 {
     
 }

2.全局Using指令(C#10)

(1):将global修饰符添加到using前,这个命名空间就应用到整个项目,不用重复using.

(2):通常创建一个专门用来编写全局using代码的C#文件

(3):如果csproj中启用了<ImplicitUsings>enable</ImplicitUsings>编译器会自动隐式增加对于System、System.Linq等常用命名空间的引入,不同各类型项目引入的命名空间也不一样。(vs2022默认都是启用的)可以手动关闭。推荐启用。

3.Using资源管理的问题

(1):之前实现了IDisposable接口的对象可以用using进行管理。

(2):如果一段代码中有很多非托管资源需要被释放的话,代码中就会存在着多个嵌套的using语句

(3):在实现了IDisposable, IAsyncDisposable接口的类型的变量声明前加上using,当代码执行离开变量的作用域时,对象就会被释放。

 //如下这样写即可 不用用()包含了
 using var ctx = new TestDbContext();
 ​
 //但是这样写也会有坑 比如
 using var outStream = File.OpenWrite(@"d:/1.txt");
 using var writer = new StreamWriter(outStream);
 writer.WriteLine("测试打印ssssssssss");
 string s = File.ReadAllText(@"d:/1.txt");
 Console.WriteLine(s);
 //此时资源并没有得到释放 可以将代码修改成如下
 ​
 //用{ }决定作用域
 using var outStream = File.OpenWrite(@"d:/1.txt");
 {
     using var writer = new StreamWriter(outStream);
     writer.WriteLine("测试打印ssssssssss");
 }
 string s = File.ReadAllText(@"d:/1.txt");
 Console.WriteLine(s);

4.文件范围的命名空间声明(C#10)

(1):之前的版本的C#中,类型必须定义在namespace中

(2):现在

 namespace TMS.Admin;
 class Teacher
 {
   public int Id { get; set; }
   public string Name { get; set; }
 }

5.可空的引用类型(C#8)

知识点

(1):C#数据类型分为值类型和引用类型两种,值类型的变量不可以为空,而引用类型变量可以为空。

(2):如果不注意检查引用类型变量是否可空,就有可能造成程序中出现 NullReferenceException异常

VS2022

(1):csproj中 <Nullable>enable</Nullable>启用可空引用类型检查(默认启用,推荐不修改)

(2):在引用类型后添加“?”修改符来声明这个类型是可空的,对于没有添加“?”修饰符的引用类型的变量,如果编译器发现存在为这个变量赋值null的可能性的时候,编译器会给出警告信息

(3):可以在警告对应的地方后面加上“!”告诉编译器不会为空,这样可以消除警告,不推荐使用。推荐对对象进行null判断。

6.记录(record)类型(C#9)//重要

(1):C#中的“= =”运算符默认是判断两个变量指向的是否同一个对象,即使两个对象的内容完全一样,也不相等。可以通过重写Equals方法,重写“= =”运算符等来解决这个问题,不过需要开发人员编写非常多的额外代码。

(2):在C#9中增加了记录(record)类型的语法,编译器会为我们自动生成Equals、GetHashcode等方法。

(3):编译器会根据Person类型中的属性定义,自动为Person类型生成包含全部属性的构造方法。注意,默认情况下,编译器会生成一个包含所有属性的构造方法,因此,因此我们编写new Person()、new Person(“yang”)这两种写法都是不可以的,也会生出ToString方法和Equals等方法。

(4):通过反编译看背后原理。避免反编译器的优化,需要把反编译器生成的代码改成C#8.0的语法,结论:record就是一个普通的类。

(5):record数据类型为我们提供了为所有属性赋值的构造方法,所有属性都是只读的,而且对象可以进行值相等的比较,并且提供了可读性强的ToString()返回值(打印所有的属性和值,不再是默认的打印类名)。在需要编写一些不可变类并且需要进行对象值比较的对象时候,record可以帮我们把代码的编写难度大大降低。

(6):可以实现部分属性是只读的、而部分属性是可以读写的。不推荐使用

(7):默认生成的构造方法的行为不能修改,我们可以为类型提供多个构造方法,然后其他构造方法通过this调用默认的构造方法。

(8):也推荐使用只读属性的类型。这样的所有属性都为只读的类型叫做“不可变类型’,可以让程序逻辑简单,减少并发访问,状态管理等的麻烦。

(9):record也是普通类,变量的赋值是引用的传递。这是和结构体不同之处。

(10):生成一个对象的副本(引用不同,值相同),这个对象的其他属性值与原对象的相同,只有一个或者少数几个属性改变

 //麻烦的写法:
 User u2 = new User(u1.UserName,"test@example",u1.Age);
 //with 关键字简化
 User u2 = u1 with{Email = "test@example"};//创建的也是拷贝
定义一个record Person
 internal record Person(string Id,string Name,string NickName);
Program:
 Person p = new Person("1","first","sao");
 Person p1 = p;
 Console.WriteLine(p.ToString());
 Console.WriteLine(p == p1);
 Console.WriteLine(Object.ReferenceEquals(p,p1));
 Person p2 = p with { };
 Console.WriteLine(p2.ToString());
 Console.WriteLine(p == p2);
 Console.WriteLine(Object.ReferenceEquals(p,p2));
 Console.WriteLine("hello");

结果如图:

反编译结果
 // Person
 using System;
 using System.Collections.Generic;
 using System.Runtime.CompilerServices;
 using System.Text;
 ​
 [System.Runtime.CompilerServices.NullableContext(1)]
 [System.Runtime.CompilerServices.Nullable(0)]
 internal class Person : IEquatable<Person>
 {
  protected virtual Type EqualityContract
  {
  [CompilerGenerated]
  get
  {
  return typeof(Person);
  }
  }
 ​
  public string Id { get; set/*init*/; }
 ​
  public string Name { get; set/*init*/; }
 ​
  public string NickName { get; set/*init*/; }
 ​
  public Person(string Id, string Name, string NickName)
  {
  this.Id = Id;
  this.Name = Name;
  this.NickName = NickName;
  base..ctor();
  }
 ​
  public override string ToString()
  {
  StringBuilder stringBuilder = new StringBuilder();
  stringBuilder.Append("Person");
  stringBuilder.Append(" { ");
  if (PrintMembers(stringBuilder))
  {
  stringBuilder.Append(' ');
  }
  stringBuilder.Append('}');
  return stringBuilder.ToString();
  }
 ​
  protected virtual bool PrintMembers(StringBuilder builder)
  {
  RuntimeHelpers.EnsureSufficientExecutionStack();
  builder.Append("Id = ");
  builder.Append((object)Id);
  builder.Append(", Name = ");
  builder.Append((object)Name);
  builder.Append(", NickName = ");
  builder.Append((object)NickName);
  return true;
  }
 ​
  [System.Runtime.CompilerServices.NullableContext(2)]
  public static bool operator !=(Person left, Person right)
  {
  return !(left == right);
  }
 ​
  [System.Runtime.CompilerServices.NullableContext(2)]
  public static bool operator ==(Person left, Person right)
  {
  return (object)left == right || ((object)left != null && left.Equals(right));
  }
 ​
  public override int GetHashCode()
  {
  return ((EqualityComparer<Type>.Default.GetHashCode(EqualityContract) * -1521134295 + EqualityComparer<string>.Default.GetHashCode(Id)) * -1521134295 + EqualityComparer<string>.Default.GetHashCode(Name)) * -1521134295 + EqualityComparer<string>.Default.GetHashCode(NickName);
  }
 ​
  [System.Runtime.CompilerServices.NullableContext(2)]
  public override bool Equals(object obj)
  {
  return Equals(obj as Person);
  }
 ​
  [System.Runtime.CompilerServices.NullableContext(2)]
  public virtual bool Equals(Person other)
  {
  return (object)this == other || ((object)other != null && EqualityContract == other.EqualityContract && EqualityComparer<string>.Default.Equals(Id, other.Id) && EqualityComparer<string>.Default.Equals(Name, other.Name) && EqualityComparer<string>.Default.Equals(NickName, other.NickName));
  }
 ​
  public virtual Person <Clone>$()
  { 
return new Person(this); 

​ 
protected Person(Person original) 

Id = original.Id; 
Name = original.Name; 
NickName = original.NickName; 

​ 
public void Deconstruct(out string Id, out string Name, out string NickName) 

Id = this.Id; 
Name = this.Name; 
NickName = this.NickName; 

}

7.init 代表只能初始化的时候赋值

 public string Id { get; set/*init*/; }
 

C#新语法的更多相关文章

  1. [C#] 回眸 C# 的前世今生 - 见证 C# 6.0 的新语法特性

    回眸 C# 的前世今生 - 见证 C# 6.0 的新语法特性 序 目前最新的版本是 C# 7.0,VS 的最新版本为 Visual Studio 2017 RC,两者都尚未进入正式阶段.C# 6.0 ...

  2. qt5中信号和槽的新语法

    qt5中的连接 有下列几种方式可以连接到信号上 旧语法 qt5将继续支持旧的语法去连接,在QObject对象上定义信号和槽函数,及任何继承QObjec的对象(包含QWidget). connect(s ...

  3. Qt 5.0+ 中 connect 新语法与重载函数不兼容问题的解决方法,以及个人看法

    Qt 5.0+ 版本提供了 connect 的新语法,相比之前的语法新语法可以提供编译期检查,使用也更方便.可是使用过程中发现一个小问题——当某个 signal 和成员函数是重载关系的时候,qmake ...

  4. .NET中那些所谓的新语法之一:自动属性、隐式类型、命名参数与自动初始化器

    开篇:在日常的.NET开发学习中,我们往往会接触到一些较新的语法,它们相对以前的老语法相比,做了很多的改进,简化了很多繁杂的代码格式,也大大减少了我们这些菜鸟码农的代码量.但是,在开心欢乐之余,我们也 ...

  5. .NET中那些所谓的新语法之二:匿名类、匿名方法与扩展方法

    开篇:在上一篇中,我们了解了自动属性.隐式类型.自动初始化器等所谓的新语法,这一篇我们继续征程,看看匿名类.匿名方法以及常用的扩展方法.虽然,都是很常见的东西,但是未必我们都明白其中蕴含的奥妙.所以, ...

  6. .NET中那些所谓的新语法之三:系统预定义委托与Lambda表达式

    开篇:在上一篇中,我们了解了匿名类.匿名方法与扩展方法等所谓的新语法,这一篇我们继续征程,看看系统预定义委托(Action/Func/Predicate)和超爱的Lambda表达式.为了方便码农们,. ...

  7. .NET中那些所谓的新语法之四:标准查询运算符与LINQ

    开篇:在上一篇中,我们了解了预定义委托与Lambda表达式等所谓的新语法,这一篇我们继续征程,看看标准查询运算符和LINQ.标准查询运算符是定义在System.Linq.Enumerable类中的50 ...

  8. 1、ASP.NET MVC入门到精通——新语法

    本系列目录:ASP.NET MVC4入门到精通系列目录汇总 在学习ASP.NET MVC之前,有必要先了解一下C#3.0所带来的新的语法特性,这一点尤为重要,因为在MVC项目中我们利用C#3.0的新特 ...

  9. 总结常见的ES6新语法特性

    前言 ES6是即将到来的新版本JavaScript语言的标准,他给我们带来了更"甜"的语法糖(一种语法,使得语言更容易理解和更具有可读性,也让我们编写代码更加简单快捷),如箭头函数 ...

  10. 队列与DelphiXe新语法

    好久没写代码了,更久没上博客园的博客了,无聊写几行试一下新语法. 1 unit Main; interface uses Winapi.Windows, Winapi.Messages, System ...

随机推荐

  1. HJ92 在字符串中找出连续最长的数字串

    描述 输入一个字符串,返回其最长的数字子串,以及其长度.若有多个最长的数字子串,则将它们全部输出(按原字符串的相对位置) 本题含有多组样例输入. 输入描述: 输入一个字符串. 输出描述: 输出字符串中 ...

  2. OM6621P系列国产M4F内核低功耗BLE5.1 SoC蓝牙芯片

    随着5G与物联网时代到来,智慧城市.电动出行.智能家居.可穿戴设备等应用高速发展,低功耗蓝牙技术在近几年智能化浪潮中的地位也尤为重要.OM6621P系列的开发即是为解决国内低功耗蓝牙应用设计需求,其主 ...

  3. ES6-新增方法

    一.字符串的新增方法 1.includes方法(实例的方法): 应用: 代码优化: (1)先使用includes方法判断是url中否包含? (2)如果包含?, 再判断url最后一位字符是不是?或&am ...

  4. Delphi 新语法:匿名函数

    这里的新语法一般指Delphi7不支持的语法. 对于比较简单实现,不需要复用,开发者更喜欢在使用时,原地声明,而没有必要单独声明并实现这个方法. 通过关键字reference来定义一个匿名函数. 下面 ...

  5. 230219 Business 1-30

    1: Packing for a Business TripWhat should I bring on this business trip?Haven't you been on a busine ...

  6. Jenkins自动化部署(linux环境)---构建任务

    用jenkins创建一个构建任务 1.这里我代码仓库用的是码云(github也是一样的)输入仓库地址.因为仓库是私有的所以会有报错提示 这里要添加Credentials.就是你码云或者github账号 ...

  7. 所谓的安装phpmyadmin

    所谓的安装phpmyadmin, 或者 安装drush, 都是下载一个文件, 然后URL访问或者命令行访问这个文件, 进入到某个页面或者获得某个结果.刚开始觉得很神秘哦, 为什么?--安装软件分两种1 ...

  8. JVM系列(四):GC策略

    一.概念 GC,Garbage Collection垃圾回收,主要针对JVM中的堆和方法区,而JVM栈.本地方法栈,程序计数器都是线程私有的,跟随线程生命周期. 二.对象存活判断 1. 引用计数:每个 ...

  9. mysql redis 开启远程访问

    springboot 加载外部yml nohup java -jar warehouse-0.0.1-SNAPSHOT.jar --Dspring.config.location=/root/www/ ...

  10. Zookeeper ZAB协议

    这篇博客是从源码的角度了解Zookeeper 从接收客户端请求开始,到返回数据为止,有很多涉及到的对象创建因为在前几篇文章已经说明过了,这里就不再重复的说明了,如果不是很明白的的,可以先看前几篇博文了 ...