C# 10.0 向 C# 语言添加了以下功能和增强功能:

1、record struct(记录结构)

C# 9 有一个新的数据类型,叫做记录(Record)。这个类型是一种特殊的引用类型,我们只需要给出一个东西的具体属性,就可以自动为这个类型生成指定的比较器(Equals 方法、比较运算符 operator == 和 operator !=、GetHashCode 方法,甚至是 ToString 方法等等)。

举个例子,我们可以这么写:

public sealed record Point(int X, int Y);

这就等价于一个类 Point,然后生成 X 和 Y 属性,以及相关的方法:

public sealed class Point
{
public int X { get; init; }
public int Y { get; init; } public override string ToString() => $"Point {{ X = {X}, Y = {Y} }}";
public override bool Equals(object? obj) => obj is Point p && p.X == X && p.Y == y;
public override int GetHashCode() => HashCode.Combine(X, Y); public static bool operator ==(Point l, Point r) => l.Equals(r);
public static bool operator !=(Point l, Point r) => !(l == r);
}

这样的东西。你看看,就写一句话就能生成一系列的内容,是不是很方便。

不过,Point 类型就俩属性,显然没有必要定义成类,因为它太轻量级了。因此,C# 10 开始允许结构记录类型。

public record struct Point(int X, int Y);

这样就好比把前文的 sealed class 改写成 struct。因此 C# 10 开始允许结构的记录类型,所以更轻量级,灵活度更高了。当然,C# 10 依然允许引用类型(类)的记录类型,你可以使用 record 或者 record class 来表示一个类的记录类型。

首先自然是 record struct,解决了 record 只能给 class 而不能给 struct 用的问题:
record struct Point(int X, int Y);
用 record 定义 struct 的好处其实有很多,例如你无需重写 GetHashCode 和 Equals 之类的方法了。
sealed record ToString 方法
之前 record 的 ToString 是不能修饰为 sealed 的,因此如果你继承了一个 record,相应的 ToString 行为也会被改变,因此这是个虚方法。
但是现在你可以把 record 里的 ToString 方法标记成 sealed,这样你的 ToString 方法就不会被重写了。

2、struct 无参构造函数

struct S0
{
object x = null;
object y;
// ok
} struct S1
{
object x = null;
object y;
S() { } // error: field 'y' must be assigned
} struct S2
{
object x = null;
object y;
S() : this(null) { } // ok
S(object y) { this.y = y; } // ok
}
struct Foo
{
public int X;
public Foo() { X = 1; }
}

一直以来 struct 不支持无参构造函数,现在支持了:

这个例子展示了无参构造器的使用方式。显然,跟引用类型是基本一样的,只是多了一点:如果你不定义的话,默认会生成一个无参构造器(S0 结构,y 会被自动赋值默认数值 default(object),也就是 null);但一经定义,就必须给所有没有赋值的字段和属性赋值。

当然,此时的构造器既然允许自定义了,这样就使得构造器可以定义和修改访问修饰符了。如果访问修饰符设置为 private 的话,那么外部就无法使用 new 来实例化该类型的对象了。这一点和引用类型还是一样的。

但是使用的时候就要注意了,因为无参构造函数的存在使得 new struct() 和 default(struct) 的语义不一样了,例如 new Foo().X == default(Foo).X 在上面这个例子中将会得出 false

2.1、结构的字段初始化器

可以看到,这个特性一旦出现,就相当于诞生了另外一个特性:结构的字段初始化器。C# 早期同样是不允许你给字段设置默认数值的;相反,你必须在构造器里赋值,还不能是默认的无参构造器里。

2.2、default(T) 表达式

另外,由于值类型和引用类型的默认数值不同的关系,定义了无参构造器必然会影响到它的默认数值
default(T) 表达式。实际上真的是这样吗?并不是。还是拿 Point
类型举例。即使你给出了默认构造器的调用,default(Point) 依旧还是原始数据的原始数据类型的默认数值构造成的实例的结果。

readonly struct Point
{
public Point() { X = int.MinValue; Y = int.MinValue; } public int X { get; }
public int Y { get; }
}

那么,default(Point) 还是 Point { X = 0, Y = 0 },而不是 Point { X = -2147483647, Y = -2147483647 } 的这个新结果。

我们把“原始数据的原始数据类型的默认数值构造成的实例”叫做零初始化实例(Zeroed
Instance),那么,default(T)
的定义就可以缩减为“该类型的零初始化实例”;换句话说,该类型的零初始化实例就是这个值类型的默认数值。那么,使用 default
表达式的时候,就算你定义了无参构造器,编译器也会始终忽略它。

3、常量字符串插值

C# 6 诞生的内插字符串并不能直接当成常量使用。举个例子:
const string A = "Sunnie";
const string B = $"Hello, {A}"; // Here

这个写法对吗?从道理上是说得通的。但是,这个写法不对。因为内插字符串没有得到编译器认为其是常量的允许,因此 B 这里会产生编译器错误。所以,你不得不改成加法运算

const string B = "Hello, " + A; // OK. 

C# 10 开始允许这一点,内插字符串也可以认为是常量了;当然前提是,内插的部分也都得是常量才行;而且内插的对象必须也得是 string 才行。

4、内插字符串处理程序

C# 10 增加了对自定义内插字符串处理程序的支持。 内插字符串处理程序是处理内插字符串中的占位符表达式的一种类型。 如果没有自定义处理程序,占位符的处理方式与 String.Format 类似。 每个占位符的格式设置为文本,然后将各组成部分串联起来,形成最终的字符串。

详细请看:https://docs.microsoft.com/zh-cn/dotnet/csharp/whats-new/tutorials/interpolated-string-handler

5、全局的 using

可将 global 修饰符添加到任何 using 指令,以指示编译器该指令适用于编译中的所有源文件。 这通常是项目中的所有源文件。

global using IntegerList = System.Collections.Generic<int>;

那么,整个项目就都可以使用这个 IntegerList 了。

6、命名空间

C# 10 开始你将能够在文件顶部指定该文件的 namespace,一个源文件只能包含一个namespace MyProject;声明。而不需要写一个 namespace 然后把其他代码都嵌套在大括号里面,毕竟绝大多数情况下,我们在写代码时一个文件里确实只会写一个 namespace,这样可以减少一层嵌套也是很不错的。

但是,原始的写法是允许嵌套命名空间和并排命名空间的,而一旦使用 namespace 指令后,就不可在文件里多次声明嵌套或并行的命名空间了。

namespace MyProject;

class MyClass
{
// ...
}

7、元组表达式里内联变量定义

这句话不好理解。举个例子。
int age;
(name, age) = student;
假如,name 是本身就有的东西(它可能是属性,或者是字段,或者是临时变量),而 age 仅仅是一个临时变量。如果你要把右侧的 student 变量解构了的话,由于 age 的定义变量语句无法写到赋值语句里面去,所以只能分开成两行书写。
C# 10 将允许你内嵌定义语句到值元组赋值的语句里去。
(name, int age) = student;
这样就合二为一了。name 照旧赋值,而 age 则完成了定义变量和赋值两个操作,且都在这一行里就可以完成。方便了不少。

lambda 改进

这个改进可以说是非常大,我分多点介绍。

1、支持 attributes

lambda 可以带 attribute 了:

f = [Foo] (x) => x; // 给 lambda 设置
f = [return: Foo] (x) => x; // 给 lambda 返回值设置
f = ([Foo] x) => x; // 给 lambda 参数设置

2、支持指定返回值类型

此前 C# 的 lambda 返回值类型靠推导,C# 10 开始允许在参数列表最前面显示指定 lambda 类型了:

f = int () => 4;

3、支持 ref 、in 、out 等修饰

f = ref int (ref int x) => ref x; // 返回一个参数的引用

4、头等函数

函数可以隐式转换到 delegate,于是函数上升至头等函数:

void Foo() { Console.WriteLine("hello"); }
var x = Foo;
x(); // hello

5、自然委托类型

lambda 现在会自动创建自然委托类型,于是不再需要写出类型了。

var f = () => 1; // Func<int>
var g = string (int x, string y) => $"{y}{x}"; // Func<int, string, string>
var h = "test".GetHashCode; // Func<int>

CallerArgumentExpression

现在,CallerArgumentExpression 这个 attribute 终于有用了。借助这个 attribute,编译器会自动填充调用参数的表达式字符串,例如:

void Foo(int value, [CallerArgumentExpression("value")] string? expression = null)
{
    Console.WriteLine(expression + " = " + value);
}

当你调用 Foo(4 + 5) 时,会输出 4 + 5 = 9。这对测试框架极其有用,因为你可以输出 assert 的原表达式了:

static void Assert(bool value, [CallerArgumentExpression("value")] string? expr = null)
{
    if (!value) throw new AssertFailureException(expr);
}

tuple 支持混合定义和使用

比如:

int y = 0;
(var x, y, var z) = (1, 2, 3);

于是 y 就变成 2 了,同时还创建了两个变量 x 和 z,分别是 1 和 3 。

8、C#新写法,默认文件内容都是写在Main函数中,C#支持本地函数。所以里面文件中函数其实是本地函数

 
Console.WriteLine("该程序接收多个参数 用空格 来做参数分隔符");
Console.WriteLine($"main函数参数agrs 的长度{args.Length} ");
int i = 1;
foreach (var s1 in args)
{
Console.WriteLine($"参数{i++}:{s1}"); } Console.WriteLine(args);
Console.ReadKey();
Count();
void Count()
{ Console.WriteLine("sdfsdf"); } void Count1(string ser)
{ Console.WriteLine("sdfsdf"); }

通过IL反编译后结果

C#10 新功能的更多相关文章

  1. What's new in Windows 10 Enterprise with Microsoft Edge.(Windows 10 新功能)

    What's new in Windows 10 Enterprise with Microsoft Edge --带有Edge浏览器的Windows 10 企业版的新功能 本文摘录自公司群发邮件, ...

  2. Windows 10新功能

    Windows 10 中面向开发人员的新增功能 Windows 10 及新增的开发人员工具将提供新通用 Windows 平台支持的工具.功能和体验.在 Windows 10 上安装完工具和 SDK后, ...

  3. Windows 10 新功能

    一.与 Cortana 集成的便笺 借助便笺,你可捕捉并保存绝妙创意或记录重要细节.便笺现已与 Cortana 集成,让你能够设置整个设备中的提醒. (一)   先来了解一下微软小娜Cortana. ...

  4. .NET6系列:C#10新功能预览

    系列目录     [已更新最新开发文章,点击查看详细] 2021年4月19日微软发布公告称将于今年夏季发布首款64位的 Visual Studio 2022,2021年5月20日又发布了 Visual ...

  5. Java 17 将要发布,补一下 Java 13 中的新功能

    本文章属于Java 新特性教程 系列,已经收录在 Github.com/niumoo/JavaNotes ,点个赞,不迷路. 自从 Oracle 调整了 Java 的版本发布节奏之后,Java 版本发 ...

  6. iOS 10正式发布:十大新功能,更注重人性化

    6月14日凌晨消息,苹果公司举行2016年WWDC全球开发者大会,介绍了watch OS.tv OS.OS X以及iOS 10系统的新特性. 据苹果介绍,iOS 10在锁屏.Siri.地图等十个各方面 ...

  7. Win 10更新版1709有哪些新功能值得关注!

    windows 10秋季创意者更新版1709发布已经有段时间了,也有很多用户选择升级这次更新的系统.那么,这次Win 10 更新版1709有哪些新功能值得关注呢?下面,一起随主机吧来看一看吧! 1. ...

  8. RAD Studio 10.3.2七大新功能介绍

    RAD Studio 10.3.2七大新功能 Delphi支持macOS 64位应用的开发. C++Builder中Windows 64位平台支持C ++ 17特性. C ++ LSP 代码洞察改进. ...

  9. Windows 10 20H1 2004新功能

    Windows 10的年度更新版本20H1即将问世.目前可以从insider preview渠道中获得.这个版本中看上去对搜索功能做了不小的改进.包括搜索的磁盘占用率以及搜索的一些展示方式. 其它的一 ...

随机推荐

  1. Spring boot + Vue axios 文件下载

    后端代码: @GetMapping("/{sn}") @ApiOperation(value = "获取文件",notes = "获取文件" ...

  2. golang反射reflect机制用法

    package main import ( "fmt" "reflect" ) type User struct { Id int Name string Ag ...

  3. Maven作用及安装

    与传统开发项目相比使用Maven: 1)Maven可以管理jar文件 2)自动下载jar和它的文档,源代码 3)管理jar直接的依赖,a.jar需要b.jar,maven会自动下载b.jar 4)管理 ...

  4. 一个简单的javaweb项目模板

    Controller包:表现层(视图)层.用来显示数据和接收用户数据 Service包:业务逻辑层,用来处理页面.先写接口,后写实现类 Dao包:持久层(数据访问层).用来操作数据库 其中Dao包处于 ...

  5. Typora基础快捷键使用流程

    Typora简介 Typora是一个所见即所得的Markdown格式文本编辑器,支持windows.macOS和GNU\Linux操作系统,包括对GitHub Flavored Markdown扩展格 ...

  6. python33day

    内容回顾 概念 同步异步阻塞和非阻塞 同步阻塞:调用一个函数需要等待这个函数的执行结果,并且在执行这个函数的过程中CPU不工作 inp=input('>>>') 同步非阻塞:调用一个 ...

  7. 随机UA

    from fake_useragent import UserAgent ua = UserAgent().random headers={ 'User-Agent':ua } print(heade ...

  8. mvvm与mvc的定义与区别

    mvvm: 即Model-View-ViewModel(模型-视图-视图模型)的简写. 模型(Model):后端传递的数据 视图(View):即前端渲染的页面 视图模型:是 mvvm 的核心,是连接 ...

  9. 布客&#183;ApacheCN 编程/大数据/数据科学/人工智能学习资源 2020.1

    公告 我们正在招募项目负责人,完成三次贡献可以申请,请联系片刻(529815144).几十个项目等你来申请和参与,不装逼的朋友,我们都不想认识. 薅资本主义羊毛的 CDNDrive 计划正式启动! 我 ...

  10. elasticsearch查询之大数据集分页性能测试

    一.测试环境 python 3.7 elasticsearch 6.8 elasticsearch-dsl 7 安装elasticsearch-dsl pip install elasticsearc ...