天天看點

C# 9 新特性 —— 補充篇

More about C# 9

C# 9 新特性 —— 補充篇

Intro

前面我們分别介紹了一些 C# 9 中的新特性,還有一些我覺得需要了解一下的新特性,寫一篇作為補充。

Top-Level Statements

在以往的代碼裡,一個應用程式必須要有

Main

方法才能運作,從 C# 9 開始,支援沒有

Main

方法的程式,實際編譯之後還是會有一個

Main

方法的,使用示例如下:

using static System.Console;

WriteLine("Hello World!");
           

實際編譯出來的結果如下:

C# 9 新特性 —— 補充篇

實際會生成一個沒有命名空間的

<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)
C# 9 新特性 —— 補充篇
C# 9 新特性 —— 補充篇

來看反編譯的代碼,可以看到有一個

Module

的類,在這個

Module

類的靜态構造方法裡會去調用聲明為

ModuleInitializer

的方法

C# 9 新特性 —— 補充篇

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

本文版權歸作者和部落格園共有,歡迎轉載,但未經作者同意必須保留此段聲明,且在文章頁面明顯位置給出原文連接配接,否則保留追究法律責任的權利。