Open7
Modern C# 2024 Edition
ピン留めされたアイテム
-
「モダンC#2024」の定義
- 現在(2024)から5年以内にC#に追加された記法・文法・APIを使うもの
-
モダンC#2024に含まれないもの(モダンC#2024では「基本」になるもの)
-
LINQ
、ラムダ式 : C#3.0 2007 -
async
/await
: C#5.0 2012 -
null
条件演算子 : C#6.0 2015 - タプル記法 /
ValueTuple
: C#7.0 2017 -
Span<T>
: C#7.2 2017
-
パターンマッチングと対応構文
- パターンマッチングはC#7.0から入り始め、C#11.0まで順に追加されている
- 一部今回の厳密な「モダンC#」基準が外れるが、まとめて説明
- それぞれのパターンに対応する記法・文法もC#に追加され、影響はC#全般に渡る
パターンマッチング後のモダンC#の特徴
- 変数スコープが変更
- キャスト(
(T)
やas
)を使うことがまれに - switch式と網羅性チェック
対応表
パターン | パターンの例 | 対応する記法・文法・API |
---|---|---|
型パターン(C#7) | obj is int |
- |
宣言パターン(C#7) | obj is int intObj |
- |
定数パターン(C#7) | obj is false |
- |
ReadOnlySpan<char> の文字列リテラル定数パターン(C#11) |
span is "abc" |
ReadOnlySpan<T> |
var パターン |
obj is var newValue |
var |
破棄パターン(C#8.0) | _ |
- |
リレーショナルパターン(C#9.0) | >= 3 and < 6 |
- |
論理パターン(C#9.0) | obj is A and B |
and /or /not
|
プロパティ パターン(C#8.0) | segment is { Start.Y: 0 } |
オブジェクト初期化子 |
位置指定パターン(C#8.0) | (0, 0) |
コンストラクタ、タプル記法、分解 |
リスト パターン(C#11) | list is [] |
Index /Range (C#8.0) , コレクション式(C#12) |
パターンマッチング全般 | - |
switch 式(C#8.0) |
モダンC#でよく使うもの
void DoSomething(string? x)
{
//早期リターン
if(x is not string x2){ return; }
Console.WriteLine(x2);
if(x is not {} x3){ return; }
Console.WriteLine(x3);
}
void DoSomething2(int? x)
{
//nullチェック&変数宣言
if(x is {} x2)
{
x2 += 10;
}else
{
//ここもx2のスコープ
x2 = 0;
}
//実はここもx2のスコープ
Console.WriteLine(x2);
}
シンプルプログラム
- 省略・スクリプトライク
- global using
- Mainメソッドの省略
- クラスの省略
- using alias C#12
- record, record struct
- プライマリコンストラクタ
- インデントが1段階減らせる
- file scope namespace
- using宣言
- 共通構文
-
Index
/Range
([a..b]
) - コレクション式
-
- 生文字列リテラル
- ソースジェネレータ
表
推奨 | 非推奨例外 | |
---|---|---|
namespace |
namespace A; |
namespace A{ }
|
using |
using var a = new A(); |
using(var a = new A()){ }
|
null安全
- C#8.0で「null安全」に
-
#nullable enable
or<Nullable>enable</Nullable>
-
??=
演算子も8.0から - そろそろ「モダン」は卒業して「基本」になりそう
[.NET API] Native AOT Ready
- モダンC#2024ではNativeAOTに対応しているかどうか、も重要な視点に
- 特にライブラリの場合
- 普通のアプリでも速度や起動時間が全然変わるので影響大きい
- Native AOT Readyに書く
- リフレクション避ける
- 対応ライブラリを使う
- ソースジェネレータを使う
Native AOT ready libraries
- 定番ライブラリもまだまだ非対応があるのでちゃんと調べる
- Json
- Json.NETではなく、System.Text.Json (SG版)
- 正規表現
- Regexではなく
GeneratedRegex
- Regexではなく
- MVVM
- CommunityToolkit.MVVM ver8.3~
細かい
スプレッド要素
List<int> listA = [1,2,3];
List<int> listB = [ .. listA, 4, 5];
- JavaScriptの「スプレッド構文」、Pythonの「スター演算子」に似たもの
- コレクション式の
[]
の中で.. collection
と書くとコレクションの中身が展開される - コレクション式と同時に導入
- コレクション式の中でのみ使える記法
- Rangeと記法は似ているが厳密には別物
//listBの後ろはRange、前はspread要素
List<int> listC = [ .. listB[1..], .. listB[..1] ];
"Safe pointer"
-
ref struct
(C#8.0) - ref field / readonly ref field (C#11.0)
- Span<T>/ReadOnlySpan<T>の
ref struct
化 (C#11.0) - scoped (C#11.0)
- ref readonly 引数 (C#12.0)
- allows ref struct (C#13.0予定)
表
※ChatGPT 4oによる解説
型引数における
ref
やin
、out
の使用はC#の型システムの制約によって制限されています。以下は、型引数として使用可能かどうかを含めた更新版の表です。
キーワード | 引数(メソッドパラメータ) | 戻り値(メソッドの返り値) | ローカル変数宣言 | メソッド内の変数代入 | 型引数 |
---|---|---|---|---|---|
ref |
✔️ | ✔️ | ✔️ | ✔️ | ❌ |
readonly ref |
✔️ | ✔️ | ✔️ | ❌ | ❌ |
scoped ref |
✔️ | ❌ | ✔️ | ❌ | ❌ |
ref readonly |
❌ | ✔️ | ✔️ | ❌ | ❌ |
scoped ref readonly |
✔️ | ❌ | ✔️ | ❌ | ❌ |
ref struct |
✔️ (3) | ❌ | ✔️ | ✔️ | ❌ |
readonly ref readonly |
❌ | ✔️ | ✔️ | ❌ | ❌ |
scoped ref struct |
✔️ (3) | ❌ | ✔️ | ❌ | ❌ |
readonly ref struct |
✔️ | ❌ | ✔️ | ❌ | ❌ |
scoped readonly ref struct |
✔️ | ❌ | ✔️ | ❌ | ❌ |
in |
✔️ | ❌ | ❌ | ❌ | ❌ |
out |
✔️ | ❌ | ❌ | ✔️ | ✔️ |
説明:
-
ref
: 型引数としては使用できません。これは、参照型や値型の柔軟性が必要なため、型引数での使用は許可されていません。 -
readonly ref
: 型引数としても同様に使用できません。readonly
であっても型引数としての参照渡しには制限があります。 -
scoped ref
: 型引数には使えません。スコープの制約があるため、型引数としての使用には向いていません。 -
ref readonly
: 型引数には使えません。読み取り専用の参照渡しも型引数としては制約されます。 -
scoped ref readonly
: 同様に、型引数としては使用できません。 -
ref struct
: 構造体の型引数としては使用できませんが、ref struct
自体はローカル変数や引数として使うことができます。 -
readonly ref readonly
: 型引数には使用できません。 -
scoped ref struct
: 型引数には使用できません。 -
readonly ref struct
: 型引数には使用できません。 -
scoped readonly ref struct
: 型引数には使用できません。 -
in
: 読み取り専用の参照渡しで、引数に使えますが、型引数には使えません。 -
out
: 型引数に対してはout
キーワードが使えます。out
は、型の共変性を指定するためにジェネリック型パラメータで使用されます。
注釈:
-
(3)
ref struct
やscoped ref struct
は、スタック割り当てに関する制約が強いため、通常の型引数としては使用できません。