C#11の.NET 6.0と.NET Framework 4.8に対する互換性

# 初めに

2022年11月、.NET 7.0がリリースされ、それと同時にC#11も安定版として使えるようになった。
C#11の各種機能は.NET 7.0ならば問題なく使用可能だが、それ以前のバージョン(.NET 6や.NET Framework)の場合、そのままでも使えるものと扱いに注意が必要なものがある。
ただし、基本的にSDKがデフォルトで設定するLangVersion以外で使用する場合は基本的に自己責任という事に注意は必要。
デフォルトが設定されているのはそれなりに理由があるものなのである。
ただし、どうしても使いたい人(含む自分)もいると思うので、参照しやすいようにまとめることにした。

C#11についての詳細解説はしないので、各仕様の公式解説は下記URLを参照のこと。
https://learn.microsoft.com/en-us/dotnet/csharp/whats-new/csharp-11

また、未確認飛行Cのサイトも、公式よりもわかりやすい形で解説しているので参考にしてほしい。
https://ufcpp.net/study/csharp/cheatsheet/ap_ver11/

# プロジェクト設定

まず、 [各TargetFrameworkはデフォルトでは使う言語バージョンが決まっている](https://learn.microsoft.com/en-us/dotnet/csharp/language-reference/configure-language-version) ため、C#11の各種機能を使う場合はビルド時の設定で明示的に指定する必要がある。
やり方としては、csprojのPropertyGroupに`LangVersion`を加えるということになる。
記述例は以下

```xml
<PropertyGroup>
  <!-- latestでも可 -->
  <LangVersion>11.0</LangVersion>
</PropertyGroup>
```

# 対応状況

先に新機能と互換性を記述しておくと以下のようになる。

〇: 特に意識せず使用可能
△: 追加のクラス定義等、特別対応が必要
×: 使えない(実行時エラー含む)

|機能名|net6.0|net48|
|-----|------|-----|
|File-scoped types|〇|〇|
|static virtual members interfaces|×|×|
|Generic math support|×|×|
|Pattern match `Span<char>` on a constant string|〇|△|
|Extended nameof scope|〇|〇|
|Auto-default struct|〇|〇|
|Numeric IntPtr|〇|〇|
|UTF-8 string literals|〇|△|
|Required members|△|△|
|ref fields|×|×|
|scoped ref|〇|〇|
|Raw string literals|〇|〇|
|Improved method group conversion to delegate|〇|〇|
|Warning wave 7|〇|〇|
|Generic Attributes|〇|×|
|Newlines in string interpolation expressions|〇|〇|
|List patterns|△|△|

両方〇になっているものは省き、注意が必要なものと、対応がアウトなものの解説を記述する。

## static virtual members interfaces

ランタイムレベルでnet7.0以降が必要になるのでビルドで失敗する。

## Generic math support

Generic mathで前提となるstatic virtual members interfacesがnet7.0以降のランタイムが必要なので使えない。

## Pattern match `Span<char>` on a constant string

Spanを使うので、.NET Frameworkの場合はSystem.Memoryパッケージの参照が必要。
ただし、.NET Frameworkで使うSpanはslow spanなので、性能特性がnet6.0とは異なることに注意。

## UTF-8 string literals

`u8`を付けたものは`ReadOnlySpan<byte>`となるため、System.Memoryパッケージの参照が必要。
ただし、.NET Frameworkで使うSpanはslow spanなので、性能特性がnet6.0とは異なることに注意。

## Required members

以下のクラス定義が必要。

* [CompilerFeatureRequiredAttribute](https://github.com/dotnet/runtime/blob/v7.0.0/src/libraries/System.Private.CoreLib/src/System/Runtime/CompilerServices/CompilerFeatureRequiredAttribute.cs)
* [RequiredMemberAttribute](https://github.com/dotnet/runtime/blob/v7.0.0/src/libraries/System.Private.CoreLib/src/System/Runtime/CompilerServices/RequiredMemberAttribute.cs)

なお、当然のことながらnet7.0で定義すると衝突を起こすので、プロジェクトのTargetFrameworkがnet7.0以降を含んでいる場合は、
プリプロセッサやビルド設定などで回避を行うこと。

## ref fields

ランタイムからサポートの必要があるので使用不可。
使おうとするとCS9064エラーが発生する。
セットで紹介されている`scoped ref`は実は他のTargetFrameworkでも使用は可能。

## Generic Attributes

net48に×がついているが、実はコンパイル自体は可能。
しかし、コンパイル後に`Type.GetCustomAttributes()`を実行すると、NotSupportedExceptionが発生する。
実行時のランタイムで決まるので、**netstandardでコンパイルした場合でも、実行EXEが.NET Frameworkだとエラーが出るので注意**

## List patterns

[System.Index](https://github.com/dotnet/runtime/blob/v7.0.0/src/libraries/System.Private.CoreLib/src/System/Index.cs) という型が必要なので、定義が必要。
.NET 7.0以降のTargetFrameworkだと衝突するため、ビルド設定等で回避を行うこと。

属性とは違って実装が必要になるため、dotnet/runtimeのソースそのままでは使用できないことに注意すること。

# 終わりに

当初想定していたよりも使えるが、罠も多いなというのが調べて思った所。
文字列関連なら罠も少ないので、個人的には使っていこうかなと思っている。