[メモ]C# 8/9の言語機能を.NET Frameworkで使う

C# 8/9の新機能は、コンパイラーさえ新しければ(例えばVisual Studio 2019を使えば)、ターゲット環境が.NET Frameworkでも使用できます。
(なお**推奨されない使い方です。**)

ただし、Nugetパッケージ参照が必要だったり、Shimコードが必要だったりします。

## プロジェクトファイルの編集

.NET Frameworkのデフォルト言語バージョンは7.3なので、`<PropertyGroup>`タグの中に

```xml
<LangVersion>9.0</LangVersion>
```
を足しましょう。

古いcsprojファイル形式のままでも、`<LangVersion>`を足すだけで大丈夫です。

## C# 8.0新機能

| C# 8.0                          |     | Note                                        |
| ------------------------------- | --- | ------------------------------------------- |
| 読み取り専用メンバー            | ✔   |                                             |
| 既定のインターフェイス メソッド | ✖   |                                             |
| パターン マッチングの拡張機能   | ✔   |                                             |
| using 宣言                      | ✔   |                                             |
| 静的ローカル関数                | ✔   |                                             |
| Dispose可能な ref 構造体        | ✔   |                                             |
| Null 許容参照型                 | ⚠   | コードには付けられるが、BCLが対応していない |
| 非同期ストリーム                | ⚠   | サードパーティーのパッケージが必要          |
| 非同期のDisposable              | ⚠   | サードパーティーのパッケージが必要          |
| インデックスと範囲              | ⚠   | サードパーティーのパッケージが必要[^1]      |
| null 合体割り当て               | ✔   |                                             |
| 構築されたアンマネージド型      | ✔   |                                             |
| 入れ子になった式の stackalloc   | ✔   |                                             |
| 逐次補間文字列の拡張            | ✔   |                                             |

[^1]: 例えば[IndexRange](https://www.nuget.org/packages/IndexRange/)

## C# 9.0新機能
https://github.com/dotnet/roslyn/discussions/47701#discussioncomment-79566

| C# 9.0                                              |     | Note                 |
| --------------------------------------------------- | --- | -------------------- |
| レコード                                            | ⚠   | `IsExternalInit`の定義が必要 |
| init 専用セッター                                   | ⚠   | `IsExternalInit`の定義が必要 |
| 最上位レベルのステートメント                        | ✔   |                      |
| パターン マッチングの拡張機能                       | ✔   |                      |
| ネイティブ サイズの整数                             | ✔   |                      |
| 関数ポインター                                      | ⚠   | managedポインターは可。unmanagedポインターは不可。                      |
| localsinit フラグの出力を抑制する                   | ⚠   | `SkipLocalsInit`属性の定義が必要 |
| ターゲット型の新しい式                              | ✔   |                      |
| 静的な匿名関数                                      | ✔   |                      |
| ターゲットにより型指定された条件式                  | ✔   |                      |
| 共変の戻り値の型                                    | ✖   |                      |
| foreach ループの拡張機能 GetEnueeeemerator サポート | ✔   |                      |
| ラムダ ディスカード パラメーター                    | ✔   |                      |
| ローカル関数の属性                                  | ✔   |                      |
| モジュールの初期化子                                | ⚠   | `ModuleInitializer`属性の定義が必要 |
| 部分メソッドの新機能                                | ✔   |                      |

[^2]: [IsExternalInitクラス](#IsExternalInitクラス)

### IsExternalInitクラス
```cs
namespace System.Runtime.CompilerServices
{
    internal static class IsExternalInit
    {
    }
}
```

### SkipLocalsInit属性
```cs
namespace System.Runtime.CompilerServices
{
    [System.AttributeUsage(System.AttributeTargets.Class | 
        System.AttributeTargets.Constructor | 
        System.AttributeTargets.Event | 
        System.AttributeTargets.Interface | 
        System.AttributeTargets.Method | 
        System.AttributeTargets.Module | 
        System.AttributeTargets.Property | 
        System.AttributeTargets.Struct, Inherited = false)]
    internal sealed class SkipLocalsInitAttribute : System.Attribute
    {
    }
}
```

### ModuleInitializer属性
```cs
namespace System.Runtime.CompilerServices
{
    [System.AttributeUsage(AttributeTargets.Method, Inherited = false)]
    internal sealed class ModuleInitializerAttribute : System.Attribute
    {
    }
}
```