程序地带

C# 9 新特性 —— 补充篇


C# 9 新特性 —— 补充篇
Intro

前面我们分别介绍了一些 C# 9 中的新特性,还有一些我觉得需要了解一下的新特性,写一篇作为补充。


Top-Level Statements

在以往的代码里,一个应用程序必须要有 Main 方法才能运行,从 C# 9 开始,支持没有 Main 方法的程序,实际编译之后还是会有一个 Main 方法的,使用示例如下:


using static System.Console;
WriteLine("Hello World!");

实际编译出来的结果如下:



实际会生成一个没有命名空间的 <Program>$ 的类型,类中定义的有一个名称是 <Main>$ 的静态方法


Improved discards in lambda input parameter

从 C# 7.2 开始,我们可以使用 _ 来代表一个不使用的变量,废弃变量,但是在 lambda 表达式里默认不能有同名的参数名,从 C# 9 开始,支持多个参数同时使用 _ 来表示,如下所示:


Func<int, int, int> constant = (_, _) => 42;
Attributes for local function

从 C# 9 开始,我们可以在局部方法(本地方法)上设置 Attribute


public static void MainTest()
{
InnerTest();
[MethodImpl(MethodImplOptions.Synchronized)]
void InnerTest()
{
Console.WriteLine(nameof(InnerTest));
}
}
Partition methods

在 C# 2.0 之后就支持了分部类,通常分部类会出现在动态代码生成的地方,对于想要将一个类型拆分到多个文件里,我们通常也会考虑用到分部类。


C# 3.0 开始支持了分部方法,但是功能比较弱,使用起来有一些限制:


分部类型各部分中的签名必须匹配。
方法必须返回 void。
不允许使用访问修饰符。 分部方法是隐式 private 的。

C# 9 增强了分部方法的支持,分部方法的使用,只能在一个地方有方法体,目前主要是为了 Source Generator 引入了这个语言特性,可以在一个地方定义方法,在另外一个地方实现方法体,示例如下:


partial class PartialMethod
{
public static partial void MainTest();
static partial void Test1();
}
partial class PartialMethod
{
public static partial void MainTest()
{
Test1();
Console.WriteLine("Partial method works");
}
}

符合 C# 3.0 分部方法规则的允许没有方法体,否则必须要有方法体


ModuleInitializer

Source Generator 除了上面的分部方法之外,还引入了一个 ModuleInitializer 的概念,就像它的名字,模块初始化器,当用到某个模块的时候就会调用对应的 ModuleInitializer 方法进行初始化操作


ModuleInitializer 定义如下:


namespace System.Runtime.CompilerServices
{
[AttributeUsage(AttributeTargets.Method, Inherited = false)]
public sealed class ModuleInitializerAttribute : Attribute
{
}
}

使用示例如下:


internal static class ModuleInitializerSample
{
/// <summary>
/// Initializer for specific module
///
/// Must be static
/// Must be parameter-less
/// Must return void
/// Must not be a generic method
/// Must not be contained in a generic class
/// Must be accessible from the containing module
/// </summary>
[ModuleInitializer]
public static void Initialize()
{
Console.WriteLine($"{nameof(ModuleInitializerAttribute)} works");
}
}

ModuleInitlializer 对应的方法有几个要求


必须是静态方法
不能有方法参数,无参数方法
方法没有返回值,返回类型必须是 void
不能是泛型方法
不能在泛型类中
必须能够被所在模块访问的到(至少是 internal)



来看反编译的代码,可以看到有一个 Module 的类,在这个 Module 类的静态构造方法里会去调用声明为 ModuleInitializer 的方法



Function Pointer

C# 9 支持方法指针,对委托进一步的”C++化“,进一步提升性能,属于非安全代码,使用需开启 unsafe,使用示例如下:


public static unsafe void MainTest()
{
delegate*<int, int, int> pointer = &Test;
var result = pointer(1, 1);
Console.WriteLine(result);
}
private static int Test(int num1, int num2)
{
Console.WriteLine($"Invoke in {nameof(Test)}, {num1}_{num2}");
return num1 + num2;
}
Static Anoymouse Method

C# 9 开始支持在匿名方法或者表达式前声明 static,声明 static 之后就不能使用实例变量,只能使用静态变量,如下所示:


internal class StaticAnonymousMethod
{
private readonly int num = 1;
public void MainTest()
{
// anonymous method
Action action = () => { Console.WriteLine(num); };
Action action1 = static () => { };// can not access `num`
//expression
Expression<Func<int, bool>> expression = i => i > num;
Expression<Func<int, bool>> expression1 = static i => i > 1;// can not access `num`
}
}
Covariant Return Type

C# 9 开始支持返回类型的 Covariant(协变), 对于 override 方法可返回从重写基方法的返回类型派生的类型。 这对于record和其他支持工厂方法的类型会很有用。可以参考下面的使用示例:


internal class CovariantReturnType
{
private abstract class Operation
{
}
private abstract class OperationFactory
{
public abstract Operation GetOperation();
}
private class AddOperation : Operation
{
}
private class AddOperationFactory : OperationFactory
{
// 返回类型协变,返回具体的类型而不是抽象类中声明的类型
public override AddOperation GetOperation()
{
return new();
}
}
public static void MainTest()
{
var factory = new AddOperationFactory();
factory.GetOperation();
}
}
More

除此之外还有一些小的更新特性,详细可以参考文末给出的官方文档。


Reference
https://docs.microsoft.com/en-us/dotnet/csharp/whats-new/csharp-9
https://github.com/WeihanLi/SamplesInPractice/tree/master/CSharp9Sample

版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
本文链接:https://www.cnblogs.com/weihanli/p/14244158.html

随机推荐

mongodb 的安装和基础语法笔记

mongodb的安装和基础语法笔记mongodb的安装windows下直接去官网进行下载配置系统环境变量启动服务,使用电脑中的服务进行启动netstartmongodbnetstopmo...

sendoh24 阅读(642)

file_exist()不支持中文文件名解决方法

file_exist函数不支持中文文件名解决方法增加了一句将UTF8编码转换为GB2312编码的语句,改进后可以了正确判断了:$file_dir=iconv(‘UT...

RSFeegg 阅读(913)

python安装jsdom 环境变量_Python环境安装

Python目前已支持所有主流操作系统,在Linux,Unix,Mac系统上自带Python环境,在Windows系统上需要安装一下,超简单Windows安装...

weixin_39751453 阅读(369)

react实现全选和反选_全选的实现

在很多的表单中我们都会看到有一个这样的功能,全选后进行一系列的操作。如操作前操作后简单的js实现首先要定义多选框,在表头可以使用id来定义同时添加onclick点击事件&l...

黎边 阅读(820)

JAVA:Junit4+Mockito单体测试

代码如下没有使用SpringBoot-test的MockMvc,这个项目因为是老项目所以是直接调用controller层的。基于老旧的测试case做修改。@Mock:创建一个Mockÿ...

HikoKane王 阅读(922)