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
- //docs.microsoft.com/en-us/dotnet/csharp/whats-new/csharp-9
- //github.com/WeihanLi/SamplesInPractice/tree/master/CSharp9Sample