Successfully reported this slideshow.

C# 9.0 / .NET 5.0

1

Share

Upcoming SlideShare
C# 8.0 null許容参照型
C# 8.0 null許容参照型
Loading in …3
×
1 of 64
1 of 64

C# 9.0 / .NET 5.0

1

Share

Download to read offline

Description

Visual Studio Users Community Japan 勉強会 #6
https://vsuc.connpass.com/event/192835/
にて登壇。

C# 9.0/.NET 5.0 世代の大まかな流れと、C# 9.0の主要な機能を紹介します。

Transcript

  1. 1. C# 9.0 .NET 5.0 ++C++; 岩永 信之
  2. 2. 今日話すこと • .NET 5.0/C# 9.0世代の大まかな流れ • C# 9.0の主要な機能紹介 全部は紹介できないので、全部知りたい人は 公式のLanguage Feature Status参照
  3. 3. .NET 5.0/C# 9.0世代の 大まかな流れ
  4. 4. .NET 5.0 (名称) • 単に「.NET」になりました • 略称もnet5.0 • .NET Standard 2.1と.NET Core 3.1両方の後続 • netstandard2.1, netcoreapp3.1ライブラリ参照可能 • .NET Frameworkは4.8が最終 • net5.0からは.NET Frameworkを指さなくなる • Mono (Xamarin)は.NET Coreとライブラリを共通化 • TargetFrameworkを分ける必要がなくなった
  5. 5. .NET 5.0 (platform) • 共通ライブラリを指して「net5.0」 • net5.0: プラットフォーム非依存な部分 • net5.0-windows : WPFとかWinFormsとか • net5.0-android : 旧monodroid (予定) • net5.0-ios : 旧Xamarin.iOS (予定) • net5.0-ios14.0なライブラリを net6.0-ios15.0なライブラリから参照可能
  6. 6. .NET 5.0 (年次リリース) • 1年に1回、決まった時期(11月)にリリース • 偶数バージョンだけ長期サポート(LTS)付き • 奇数バージョンはGA (Generally Available) • 「普通に使っても大丈夫だよ」くらいのニュアンス • 偶数バージョンが出たらそっちに移ってほしい 今年(.NET 5.0)はGAの年
  7. 7. .NET 5.0 (多platform対応プラン) • 共通ライブラリを指して「net5.0」 • net5.0: プラットフォーム非依存な部分 • net5.0-windows : WPFとかWinFormsとか • net5.0-android : 旧monodroid (予定) • net5.0-ios : 旧Xamarin.iOS (予定) • net5.0-ios14.0なライブラリを net6.0-ios15.0なライブラリから参照可能 これも段階的に改善予定 1. インストーラーでインストール済みのSDKのみ • .NET 5時点で、Windowsのみ • 旧Xamarinのものは .NET 6 予定 2. NuGetみたいな自動解決手段の提供
  8. 8. C# 9.0 (.NET 5世代の C#) • C#も.NETと同じく年次リリース • 1つの機能を数バージョンかけて改善していく • 数バージョンかかる大きな機能 • Nullability解析 • null許容参照型 • Working with data • パターン マッチング • レコード型 C# 9.0で一番大きいのはこれ
  9. 9. C# 9.0 (.NET 5世代の C#) • Xamarin統合※とかで用途が増えてる • Interactive実行 • リフレクションが使いづらい環境での実行 • ネイティブ相互運用の機会が増えてる ※ 完全統合は.NET 6.0予定
  10. 10. Nullability解析 nullはコンパイル時にフロー解析して排除する
  11. 11. Nullability解析 • C# 8.0 (前バージョン)~ 「nullはbillion dollar mistake」 • 参照型Tがnullを受け付けてしまうのはまずかった • 今更nullをなくせない言語でも静的解析すべき • T はnullを受け付けない • T? にした時だけnullを受け付ける • この手の解析は結構難しいので徐々に改善
  12. 12. Nullability解析 C# 8.0 (2019) C# 9.0 (今ここ) C# 10.0 (2021) (候補) ・最初のリリース ・ MemberNotNull属性 ・制約なしジェネリック T? ・ Task<T?>, IEnumerable<T?>の共変性
  13. 13. C# 9.0のnull解析: MemberNotNull • MemberNotNull属性 class A { public string Name { get; } } 非null型を初期化 していないので警告
  14. 14. C# 9.0のnull解析: MemberNotNull • MemberNotNull属性 class A { public string Name { get; } public A() => Name = "name"; } コンストラクターで 初期化すれば警告消える
  15. 15. C# 9.0のnull解析: MemberNotNull • MemberNotNull属性 class A { public string Name { get; private set; } public A() => Init(); private void Init() => Name = "name"; } 初期化をコンストラクターから メソッド抽出するとnull解析できなくなる (Nameを初期化してないと警告が出る)
  16. 16. C# 9.0のnull解析: MemberNotNull • MemberNotNull属性 class A { public string Name { get; private set; } public A() => Init(); [MemberNotNull(nameof(Name))] private void Init() => Name = "name"; } Nameの非null初期化を保証 (Aに出ていた警告が消える)
  17. 17. C# 9.0のnull解析: 制約なしT? • 制約なしT? (C# 8.0) #nullable enable class A<T> { public T? M() => default; } C# 8.0まで 制約なしのTに?は付けれない
  18. 18. C# 9.0のnull解析: 制約なしT? • class制約T? #nullable enable class A<T> where T : class { public T? M() => default; } C# 8.0まででも class(参照型)制約を付けるとOK T?はnull許容参照型 (コンパイル時の静的解析)
  19. 19. C# 9.0のnull解析: 制約なしT? • struct制約T? #nullable enable class A<T> where T : struct { public T? M() => default; } C# 8.0まででも struct(値型)制約を付けるとOK T?はnull許容値型 (Nullable<T>構造体の構文糖衣)
  20. 20. C# 9.0のnull解析: 制約なしT? • 制約なしT? (C# 9.0) #nullable enable class A<T> { public T? M() => default; } C# 9.0でこれがOKに ただ…
  21. 21. C# 9.0のnull解析: 制約なしT? • 制約なしT? は「defaultable」 public T? M() => default; 戻り値はdefault • 参照型 : null • null許容値型 : null • 非null値型 : 0 string? a = new A<string?>().M(); string? b = new A<string>().M(); int? c = new A<int?>().M(); int d = new A<int>().M(); 参照型の時は string → string? 非null値型の時は int → int (0が返る) これはnullが返る 要はLINQのFirstOrDefaultと同じ挙動
  22. 22. Working with data データ中心のプログラミング
  23. 23. Working with data • データが主役のプログラミング class Point { public int X { get; } public int Y { get; } } • 保存とか通信とかするとき こういうpublicプロパティだ け持つ型を多用 • immutableにしたい • value semanticsを持ちたい
  24. 24. value semantics • (参照型であっても)値で比較 • コピーを作って部分書き換え var x = new Point(1, 2); var y = new Point(1, 2); Console.WriteLine(x == y); true var x = new Point(1, 2); var y = x with { X = 3 }; x は {X=1, Y=2} のまま変えない 新たに {X=3, Y=2} で y を作る
  25. 25. Working with dataのボイラープレート • 真面目に書こうとすると煩雑 class Point { public int X { get; } public int Y { get; } public Point(int x, int y) { X = x; Y = y; } } immutableにしたいとき、こ の手のボイラープレート コードが多い問題 この他にもEqualsとか GetHashCodeとか Deconstructとか 同じ名前を何か所も…
  26. 26. Working with dataのための言語機能 • 言語機能のサポートが欲しい • パターン マッチングとかレコード型とかはこの一環 class Point { public int X { get; } public int Y { get; } } record Point(int X, int Y); • ボイラープレートコード削減 • 推奨する方式(immutable)を一 番短く書けるように
  27. 27. パターン マッチング C# 8.0 (2019) C# 9.0 (今ここ) C# 10.0 (2021) (候補) ・ 型パターン ・ 破棄(discard) C# 7.0 (2017) ・ 再起パターン (位置、プロパティ) ・ パターンの組み合わせ (and, or, not, ()) ・ 比較パターン (<, >, <=, >=) ・ listパターン ([])
  28. 28. C# 9.0で追加されるパターン • 組み合わせ&大小比較 int m(byte b) { if (b < 10) return 1; else if (b >= 10 && b < 100) return 2; else if (b >= 100) return 3; else return -1; } これまでのコード
  29. 29. C# 9.0で追加されるパターン • 組み合わせ&大小比較 Visual Studioの自動リファクタリング
  30. 30. C# 9.0で追加されるパターン • 組み合わせ&大小比較(網羅チェックがかかる) 変化後 int m(byte b) => b switch { < 10 => 1, >= 10 and < 100 => 2, >= 100 => 3, _ => -1 }; 読みやすい・書きやすいか というと微妙なものの… ここをエラーにしてくれる この3条件でbyteが取り うる値を全部網羅してる なので到達不能
  31. 31. パターン補足: not • not null x is not null x is { } x != null 一応、新パターン 一番「意味通り」なコードに C# 8.0のプロパティ パターンで代用 プロパティ値取得前にnullチェックが挟まる ユーザー定義 == があるときに意味が変わる (ユーザー定義のやつが呼ばれる) (not nullは常に参照比較)
  32. 32. パターン補足: not • notと変数宣言 void m(object x) { if (x is not string s) return; // else の側で s を使える Console.WriteLine(s.Length); } notの後ろで変数宣言可能 (switchでは不可。if限定)
  33. 33. パターン補足: and • and両辺の変数宣言はどちらもdefinite assigned interface IA { int X { get; } } interface IB { int Y { get; } } int m(object x) => x switch { IA a and IB b => a.X * b.Y, }; aもbも確実に初期化されてる保証あり プロパティ アクセス可能
  34. 34. パターン補足: or • orは一応、共通型判定を受ける object m(object x) => x switch { (IEnumerable or ICollection) and var e => e.GetEnumerator(), }; IEnumerableとICollectionの 共通型を一応調べてくれる この場合、eはIEnumerable (ただ、C#の「共通型」判定自体が そんなに賢くないのでそんなに役立たない)
  35. 35. レコード型 C# 9.0 (今ここ) C# 10.0 (2021) (候補) ・最初のリリース ・ Discriminated Union ・ 値型レコード (record struct (仮)) record Point(int X, int Y);
  36. 36. record • value semanticsを持つ参照型 record Point { public int X { get; } public int Y { get; } } コンパイラー生成 bool Equals(Point other) => (X, Y) == (other.X, other.Y); int GetHashCode() => HashCode.Combine(X, Y); void Deconstruct(out int x, out int y) => (x, y) = (X, Y); Clone, ToString, IEquatable<T>, ... (デフォルトで) publicなプロパティ 全部が関与
  37. 37. initプロパティ • new、Clone直後だけ書き換え可能なプロパティ record Point { public int X { get; init; } public int Y { get; init; } } setの代わりに initキーワード
  38. 38. initプロパティ • new直後? • 要するにオブジェクト初期化子 var p = new Point { X = 1, Y = 2, } p.X = 1; この行はOK この行はエラー
  39. 39. initプロパティ • new直後? • 要するにオブジェクト初期化子 var p = new Point { X = 1, Y = 2, }; p.X = 1; var p = new Point p.X = 1; p.Y = 2; コンパイラー による展開 展開結果は同じだけど コンパイル時検査で 「初期化のみ」を保証
  40. 40. initプロパティ • Clone直後? • with式: Clone + 部分書き換え var p1 = new Point { X = 1, Y = 2, } var p2 = p1 with { X = 3 }; p1は(1, 2)のまま p2は(3, 2)に
  41. 41. initプロパティ • Clone直後? • with式: Clone + 部分書き換え var p2 = p1.Clone(); p2.X = 3; var p2 = p1 with { X = 3 }; Clone直後だけ書き換え可能 (これもコンパイル時検査) ※ ※ 実際には<Clone>$みたいな名前で生成されてて with式以外からは呼べないようにしてある
  42. 42. プライマリ コンストラクター • 型名直後に引数リスト • public initプロパティとコンストラクターを生成 record Point(int X, int Y); record Point { public int X { get; init; } public int Y { get; init; } public Point(int x, int y) => (X, Y) = (x, y); }
  43. 43. プライマリ コンストラクター • 現状、record専用の構文 record Point(int X, int Y); C# 9.0 class Point(int X, int Y) { } C# 10.0 struct Point(int X, int Y) { } • プロパティ生成まではしない • メンバー初期化子で参照できる
  44. 44. recordの継承 • 継承可能 record Base; record Derived : Base;
  45. 45. recordの継承 • 継承可能 • プライマリ コンストラクターもOK record Base(int X); record Derived(int X, int Y) : Base(X); record Base(int X); record Derived() : Base(1);
  46. 46. recordの継承 • 継承可能 • Union的な使い方 record Shape; record Circle(float R) : Shape; record Rect(float W, float H) : Shape;
  47. 47. 名前付きの型と匿名の型 • 名前の有無での差を減らしたい 匿名 (anonymous) ソース型推論 ターゲット型推論 (target-typed new) 位置指定 (positional) var x = (1, 2); var x = new T(1, 2); T x = new(1, 2); 名前指定 (nominal) var x = new { X = 1, Y = 2, }; var x = new T { X = 1, Y = 2, }; T x = new() { X = 1, Y = 2, }; 匿名型(C# 3.0) タプル(C# 7.0) ターゲットからの型推論(C# 9.0) オブジェクト初期化子(C# 3.0) initプロパティ(C# 9.0)
  48. 48. target-typed new • varと逆向きに型推論 • varが使えない場所と言えば… class T { Dictionary<string, List<(int x, int y)[]> d = new(); } 多分これが一番よく使うと思います
  49. 49. discriminated union (C# 10.0予定) • recordをdiscriminated union的にしたい record Shape { Circle(float R); Rect(float W, float H); } float Area(Shape s) => s switch { Circle c => c.R * c.R * MathF.PI, Rect r => r.W * r.H, }; ※ 多分、別キーワードか 追加修飾子が必要 (これ自体はC# 9.0でも書ける) 「CircleとRectしかない」(網羅性) の判定が9.0だとできない
  50. 50. 用途の増加
  51. 51. 用途の増加: Interactive • Interactive実行 • C#入門記事に埋め込んだコードをその場で実行 • Jupyter Notebookみたいな使い方したい 1行1行入力して、 すぐに計算結果を見たい
  52. 52. 用途の増加: Interactive • Interactive実行 • C#入門記事に埋め込んだコードをその場で実行 今、C#公式チュートリアルがそうなって る
  53. 53. 用途の増加: Interactive • Interactive実行 • Jupyter Notebookみたいな使い方したい .NET Interactive Notebooks (Visual Studio Codeで書いて ipynb形式で保存可能)
  54. 54. 通常C#とinteractive C# • Interactive専用構文がいくつかあり(C# 6.0以降) • C# 9.0で通常C#とInteractive C#の差を減らしたい • top-levelプログラム using System; Console.WriteLine("Hello World!"); Program.cs これだけでコンパイル可能 Program.Main不要
  55. 55. 用途の増加: 事前コンパイル • JITコンパイルできない・したくない環境向け • iOSとかWebAssemblyとか • リフレクションが使いづらい • コード生成の類を静的(コンパイル時)に行いたい
  56. 56. Source Generator • C# 9.0でコンパイル時コード生成をサポート • C# 6.0からあるAnalyzerの延長 using System; partial class A { [StringLiteral.Utf8("😀")] public static partial ReadOnlySpan<byte> M(); } public static partial System.ReadOnlySpan<byte> M() => new byte[] {240, 159, 152, 128, }; コンパイル時にソースコード生成
  57. 57. Source Generator • C# 9.0でコンパイル時コード生成をサポート • C# 6.0からあるAnalyzerの延長 これを自作したり、 NuGet参照したりできる この例のやつは https://www.nuget.org/packages/StringLiteralGenerator/ https://github.com/ufcpp/StringLiteralGenerator
  58. 58. Source Generator • Visual Studioのサポートあり • F12で生成結果のソースコードに飛べて • F9でブレイクポイントをしかけれて • F11でステップイン実行できる
  59. 59. Source Generator • C# 9.0のpartialメソッド using System; partial class A { [StringLiteral.Utf8("😀")] public static partial ReadOnlySpan<byte> M(); } これまで(C# 2.0)のpartial • publicとかは付けない • コード生成が先にある想定 • 手書きで実装を追加(してもいい) C# 9.0の新partial • publicとかを付ける • 手書きが先にある想定 • コード生成で作る(必須)
  60. 60. Source Generator化されそうなもの(1) • C#以外からのコード生成 • Razor (cshtmlからのC#コード生成) • Grpc.Tools (protoからのC#コード生成)
  61. 61. Source Generator化されそうなもの(2) • 脱リフレクション • Jsonとかのシリアライザー • Regexの事前コンパイル • DI (コンストラクター インジェクションとか)
  62. 62. Source Generator化されそうなもの(3) • C#内でのコード生成 • PropertyChanged • recordのカスタマイズ • EqualsとかToStringとかの挙動を自分でコントロール • ガチガチの最適化 • さっき出した例(UTF-8バイト列生成)とか
  63. 63. 用途の増加: ネイティブ相互運用 • Xamarin統合で対応プラットフォームが増加 • ネイティブ相互運用が大変になったらしい • C#にもいくつか相互運用用の文法追加 • nint, nuint: CPUネイティブなint • 関数ポインター (delegate* <int, void> みたいなの) • 間接的なメリット(ほとんどの人は直接使わない) • dotnet/runtime内で使われまくる予定 • 全.NETユーザーが間接的に恩恵受ける
  64. 64. まとめ • .NET 5.0 • 年次リリース化&用途増加 • C# 9.0 • 大きな機能は少しずつ改善 • レコード型、パターン マッチング、Nullability解析 • 用途増加に対応 • top-levelプログラム、source generator

Editor's Notes

  • https://github.com/dotnet/roslyn/blob/master/docs/Language%20Feature%20Status.md
  • newの有無とか、()の有無とかで細かい不整合は残ってたりするんだけど…
  • https://docs.microsoft.com/en-us/dotnet/csharp/tutorials/
  • https://devblogs.microsoft.com/dotnet/net-interactive-preview-3-vs-code-insiders-and-polyglot-notebooks/
  • Description

    Visual Studio Users Community Japan 勉強会 #6
    https://vsuc.connpass.com/event/192835/
    にて登壇。

    C# 9.0/.NET 5.0 世代の大まかな流れと、C# 9.0の主要な機能を紹介します。

    Transcript

    1. 1. C# 9.0 .NET 5.0 ++C++; 岩永 信之
    2. 2. 今日話すこと • .NET 5.0/C# 9.0世代の大まかな流れ • C# 9.0の主要な機能紹介 全部は紹介できないので、全部知りたい人は 公式のLanguage Feature Status参照
    3. 3. .NET 5.0/C# 9.0世代の 大まかな流れ
    4. 4. .NET 5.0 (名称) • 単に「.NET」になりました • 略称もnet5.0 • .NET Standard 2.1と.NET Core 3.1両方の後続 • netstandard2.1, netcoreapp3.1ライブラリ参照可能 • .NET Frameworkは4.8が最終 • net5.0からは.NET Frameworkを指さなくなる • Mono (Xamarin)は.NET Coreとライブラリを共通化 • TargetFrameworkを分ける必要がなくなった
    5. 5. .NET 5.0 (platform) • 共通ライブラリを指して「net5.0」 • net5.0: プラットフォーム非依存な部分 • net5.0-windows : WPFとかWinFormsとか • net5.0-android : 旧monodroid (予定) • net5.0-ios : 旧Xamarin.iOS (予定) • net5.0-ios14.0なライブラリを net6.0-ios15.0なライブラリから参照可能
    6. 6. .NET 5.0 (年次リリース) • 1年に1回、決まった時期(11月)にリリース • 偶数バージョンだけ長期サポート(LTS)付き • 奇数バージョンはGA (Generally Available) • 「普通に使っても大丈夫だよ」くらいのニュアンス • 偶数バージョンが出たらそっちに移ってほしい 今年(.NET 5.0)はGAの年
    7. 7. .NET 5.0 (多platform対応プラン) • 共通ライブラリを指して「net5.0」 • net5.0: プラットフォーム非依存な部分 • net5.0-windows : WPFとかWinFormsとか • net5.0-android : 旧monodroid (予定) • net5.0-ios : 旧Xamarin.iOS (予定) • net5.0-ios14.0なライブラリを net6.0-ios15.0なライブラリから参照可能 これも段階的に改善予定 1. インストーラーでインストール済みのSDKのみ • .NET 5時点で、Windowsのみ • 旧Xamarinのものは .NET 6 予定 2. NuGetみたいな自動解決手段の提供
    8. 8. C# 9.0 (.NET 5世代の C#) • C#も.NETと同じく年次リリース • 1つの機能を数バージョンかけて改善していく • 数バージョンかかる大きな機能 • Nullability解析 • null許容参照型 • Working with data • パターン マッチング • レコード型 C# 9.0で一番大きいのはこれ
    9. 9. C# 9.0 (.NET 5世代の C#) • Xamarin統合※とかで用途が増えてる • Interactive実行 • リフレクションが使いづらい環境での実行 • ネイティブ相互運用の機会が増えてる ※ 完全統合は.NET 6.0予定
    10. 10. Nullability解析 nullはコンパイル時にフロー解析して排除する
    11. 11. Nullability解析 • C# 8.0 (前バージョン)~ 「nullはbillion dollar mistake」 • 参照型Tがnullを受け付けてしまうのはまずかった • 今更nullをなくせない言語でも静的解析すべき • T はnullを受け付けない • T? にした時だけnullを受け付ける • この手の解析は結構難しいので徐々に改善
    12. 12. Nullability解析 C# 8.0 (2019) C# 9.0 (今ここ) C# 10.0 (2021) (候補) ・最初のリリース ・ MemberNotNull属性 ・制約なしジェネリック T? ・ Task<T?>, IEnumerable<T?>の共変性
    13. 13. C# 9.0のnull解析: MemberNotNull • MemberNotNull属性 class A { public string Name { get; } } 非null型を初期化 していないので警告
    14. 14. C# 9.0のnull解析: MemberNotNull • MemberNotNull属性 class A { public string Name { get; } public A() => Name = "name"; } コンストラクターで 初期化すれば警告消える
    15. 15. C# 9.0のnull解析: MemberNotNull • MemberNotNull属性 class A { public string Name { get; private set; } public A() => Init(); private void Init() => Name = "name"; } 初期化をコンストラクターから メソッド抽出するとnull解析できなくなる (Nameを初期化してないと警告が出る)
    16. 16. C# 9.0のnull解析: MemberNotNull • MemberNotNull属性 class A { public string Name { get; private set; } public A() => Init(); [MemberNotNull(nameof(Name))] private void Init() => Name = "name"; } Nameの非null初期化を保証 (Aに出ていた警告が消える)
    17. 17. C# 9.0のnull解析: 制約なしT? • 制約なしT? (C# 8.0) #nullable enable class A<T> { public T? M() => default; } C# 8.0まで 制約なしのTに?は付けれない
    18. 18. C# 9.0のnull解析: 制約なしT? • class制約T? #nullable enable class A<T> where T : class { public T? M() => default; } C# 8.0まででも class(参照型)制約を付けるとOK T?はnull許容参照型 (コンパイル時の静的解析)
    19. 19. C# 9.0のnull解析: 制約なしT? • struct制約T? #nullable enable class A<T> where T : struct { public T? M() => default; } C# 8.0まででも struct(値型)制約を付けるとOK T?はnull許容値型 (Nullable<T>構造体の構文糖衣)
    20. 20. C# 9.0のnull解析: 制約なしT? • 制約なしT? (C# 9.0) #nullable enable class A<T> { public T? M() => default; } C# 9.0でこれがOKに ただ…
    21. 21. C# 9.0のnull解析: 制約なしT? • 制約なしT? は「defaultable」 public T? M() => default; 戻り値はdefault • 参照型 : null • null許容値型 : null • 非null値型 : 0 string? a = new A<string?>().M(); string? b = new A<string>().M(); int? c = new A<int?>().M(); int d = new A<int>().M(); 参照型の時は string → string? 非null値型の時は int → int (0が返る) これはnullが返る 要はLINQのFirstOrDefaultと同じ挙動
    22. 22. Working with data データ中心のプログラミング
    23. 23. Working with data • データが主役のプログラミング class Point { public int X { get; } public int Y { get; } } • 保存とか通信とかするとき こういうpublicプロパティだ け持つ型を多用 • immutableにしたい • value semanticsを持ちたい
    24. 24. value semantics • (参照型であっても)値で比較 • コピーを作って部分書き換え var x = new Point(1, 2); var y = new Point(1, 2); Console.WriteLine(x == y); true var x = new Point(1, 2); var y = x with { X = 3 }; x は {X=1, Y=2} のまま変えない 新たに {X=3, Y=2} で y を作る
    25. 25. Working with dataのボイラープレート • 真面目に書こうとすると煩雑 class Point { public int X { get; } public int Y { get; } public Point(int x, int y) { X = x; Y = y; } } immutableにしたいとき、こ の手のボイラープレート コードが多い問題 この他にもEqualsとか GetHashCodeとか Deconstructとか 同じ名前を何か所も…
    26. 26. Working with dataのための言語機能 • 言語機能のサポートが欲しい • パターン マッチングとかレコード型とかはこの一環 class Point { public int X { get; } public int Y { get; } } record Point(int X, int Y); • ボイラープレートコード削減 • 推奨する方式(immutable)を一 番短く書けるように
    27. 27. パターン マッチング C# 8.0 (2019) C# 9.0 (今ここ) C# 10.0 (2021) (候補) ・ 型パターン ・ 破棄(discard) C# 7.0 (2017) ・ 再起パターン (位置、プロパティ) ・ パターンの組み合わせ (and, or, not, ()) ・ 比較パターン (<, >, <=, >=) ・ listパターン ([])
    28. 28. C# 9.0で追加されるパターン • 組み合わせ&大小比較 int m(byte b) { if (b < 10) return 1; else if (b >= 10 && b < 100) return 2; else if (b >= 100) return 3; else return -1; } これまでのコード
    29. 29. C# 9.0で追加されるパターン • 組み合わせ&大小比較 Visual Studioの自動リファクタリング
    30. 30. C# 9.0で追加されるパターン • 組み合わせ&大小比較(網羅チェックがかかる) 変化後 int m(byte b) => b switch { < 10 => 1, >= 10 and < 100 => 2, >= 100 => 3, _ => -1 }; 読みやすい・書きやすいか というと微妙なものの… ここをエラーにしてくれる この3条件でbyteが取り うる値を全部網羅してる なので到達不能
    31. 31. パターン補足: not • not null x is not null x is { } x != null 一応、新パターン 一番「意味通り」なコードに C# 8.0のプロパティ パターンで代用 プロパティ値取得前にnullチェックが挟まる ユーザー定義 == があるときに意味が変わる (ユーザー定義のやつが呼ばれる) (not nullは常に参照比較)
    32. 32. パターン補足: not • notと変数宣言 void m(object x) { if (x is not string s) return; // else の側で s を使える Console.WriteLine(s.Length); } notの後ろで変数宣言可能 (switchでは不可。if限定)
    33. 33. パターン補足: and • and両辺の変数宣言はどちらもdefinite assigned interface IA { int X { get; } } interface IB { int Y { get; } } int m(object x) => x switch { IA a and IB b => a.X * b.Y, }; aもbも確実に初期化されてる保証あり プロパティ アクセス可能
    34. 34. パターン補足: or • orは一応、共通型判定を受ける object m(object x) => x switch { (IEnumerable or ICollection) and var e => e.GetEnumerator(), }; IEnumerableとICollectionの 共通型を一応調べてくれる この場合、eはIEnumerable (ただ、C#の「共通型」判定自体が そんなに賢くないのでそんなに役立たない)
    35. 35. レコード型 C# 9.0 (今ここ) C# 10.0 (2021) (候補) ・最初のリリース ・ Discriminated Union ・ 値型レコード (record struct (仮)) record Point(int X, int Y);
    36. 36. record • value semanticsを持つ参照型 record Point { public int X { get; } public int Y { get; } } コンパイラー生成 bool Equals(Point other) => (X, Y) == (other.X, other.Y); int GetHashCode() => HashCode.Combine(X, Y); void Deconstruct(out int x, out int y) => (x, y) = (X, Y); Clone, ToString, IEquatable<T>, ... (デフォルトで) publicなプロパティ 全部が関与
    37. 37. initプロパティ • new、Clone直後だけ書き換え可能なプロパティ record Point { public int X { get; init; } public int Y { get; init; } } setの代わりに initキーワード
    38. 38. initプロパティ • new直後? • 要するにオブジェクト初期化子 var p = new Point { X = 1, Y = 2, } p.X = 1; この行はOK この行はエラー
    39. 39. initプロパティ • new直後? • 要するにオブジェクト初期化子 var p = new Point { X = 1, Y = 2, }; p.X = 1; var p = new Point p.X = 1; p.Y = 2; コンパイラー による展開 展開結果は同じだけど コンパイル時検査で 「初期化のみ」を保証
    40. 40. initプロパティ • Clone直後? • with式: Clone + 部分書き換え var p1 = new Point { X = 1, Y = 2, } var p2 = p1 with { X = 3 }; p1は(1, 2)のまま p2は(3, 2)に
    41. 41. initプロパティ • Clone直後? • with式: Clone + 部分書き換え var p2 = p1.Clone(); p2.X = 3; var p2 = p1 with { X = 3 }; Clone直後だけ書き換え可能 (これもコンパイル時検査) ※ ※ 実際には<Clone>$みたいな名前で生成されてて with式以外からは呼べないようにしてある
    42. 42. プライマリ コンストラクター • 型名直後に引数リスト • public initプロパティとコンストラクターを生成 record Point(int X, int Y); record Point { public int X { get; init; } public int Y { get; init; } public Point(int x, int y) => (X, Y) = (x, y); }
    43. 43. プライマリ コンストラクター • 現状、record専用の構文 record Point(int X, int Y); C# 9.0 class Point(int X, int Y) { } C# 10.0 struct Point(int X, int Y) { } • プロパティ生成まではしない • メンバー初期化子で参照できる
    44. 44. recordの継承 • 継承可能 record Base; record Derived : Base;
    45. 45. recordの継承 • 継承可能 • プライマリ コンストラクターもOK record Base(int X); record Derived(int X, int Y) : Base(X); record Base(int X); record Derived() : Base(1);
    46. 46. recordの継承 • 継承可能 • Union的な使い方 record Shape; record Circle(float R) : Shape; record Rect(float W, float H) : Shape;
    47. 47. 名前付きの型と匿名の型 • 名前の有無での差を減らしたい 匿名 (anonymous) ソース型推論 ターゲット型推論 (target-typed new) 位置指定 (positional) var x = (1, 2); var x = new T(1, 2); T x = new(1, 2); 名前指定 (nominal) var x = new { X = 1, Y = 2, }; var x = new T { X = 1, Y = 2, }; T x = new() { X = 1, Y = 2, }; 匿名型(C# 3.0) タプル(C# 7.0) ターゲットからの型推論(C# 9.0) オブジェクト初期化子(C# 3.0) initプロパティ(C# 9.0)
    48. 48. target-typed new • varと逆向きに型推論 • varが使えない場所と言えば… class T { Dictionary<string, List<(int x, int y)[]> d = new(); } 多分これが一番よく使うと思います
    49. 49. discriminated union (C# 10.0予定) • recordをdiscriminated union的にしたい record Shape { Circle(float R); Rect(float W, float H); } float Area(Shape s) => s switch { Circle c => c.R * c.R * MathF.PI, Rect r => r.W * r.H, }; ※ 多分、別キーワードか 追加修飾子が必要 (これ自体はC# 9.0でも書ける) 「CircleとRectしかない」(網羅性) の判定が9.0だとできない
    50. 50. 用途の増加
    51. 51. 用途の増加: Interactive • Interactive実行 • C#入門記事に埋め込んだコードをその場で実行 • Jupyter Notebookみたいな使い方したい 1行1行入力して、 すぐに計算結果を見たい
    52. 52. 用途の増加: Interactive • Interactive実行 • C#入門記事に埋め込んだコードをその場で実行 今、C#公式チュートリアルがそうなって る
    53. 53. 用途の増加: Interactive • Interactive実行 • Jupyter Notebookみたいな使い方したい .NET Interactive Notebooks (Visual Studio Codeで書いて ipynb形式で保存可能)
    54. 54. 通常C#とinteractive C# • Interactive専用構文がいくつかあり(C# 6.0以降) • C# 9.0で通常C#とInteractive C#の差を減らしたい • top-levelプログラム using System; Console.WriteLine("Hello World!"); Program.cs これだけでコンパイル可能 Program.Main不要
    55. 55. 用途の増加: 事前コンパイル • JITコンパイルできない・したくない環境向け • iOSとかWebAssemblyとか • リフレクションが使いづらい • コード生成の類を静的(コンパイル時)に行いたい
    56. 56. Source Generator • C# 9.0でコンパイル時コード生成をサポート • C# 6.0からあるAnalyzerの延長 using System; partial class A { [StringLiteral.Utf8("😀")] public static partial ReadOnlySpan<byte> M(); } public static partial System.ReadOnlySpan<byte> M() => new byte[] {240, 159, 152, 128, }; コンパイル時にソースコード生成
    57. 57. Source Generator • C# 9.0でコンパイル時コード生成をサポート • C# 6.0からあるAnalyzerの延長 これを自作したり、 NuGet参照したりできる この例のやつは https://www.nuget.org/packages/StringLiteralGenerator/ https://github.com/ufcpp/StringLiteralGenerator
    58. 58. Source Generator • Visual Studioのサポートあり • F12で生成結果のソースコードに飛べて • F9でブレイクポイントをしかけれて • F11でステップイン実行できる
    59. 59. Source Generator • C# 9.0のpartialメソッド using System; partial class A { [StringLiteral.Utf8("😀")] public static partial ReadOnlySpan<byte> M(); } これまで(C# 2.0)のpartial • publicとかは付けない • コード生成が先にある想定 • 手書きで実装を追加(してもいい) C# 9.0の新partial • publicとかを付ける • 手書きが先にある想定 • コード生成で作る(必須)
    60. 60. Source Generator化されそうなもの(1) • C#以外からのコード生成 • Razor (cshtmlからのC#コード生成) • Grpc.Tools (protoからのC#コード生成)
    61. 61. Source Generator化されそうなもの(2) • 脱リフレクション • Jsonとかのシリアライザー • Regexの事前コンパイル • DI (コンストラクター インジェクションとか)
    62. 62. Source Generator化されそうなもの(3) • C#内でのコード生成 • PropertyChanged • recordのカスタマイズ • EqualsとかToStringとかの挙動を自分でコントロール • ガチガチの最適化 • さっき出した例(UTF-8バイト列生成)とか
    63. 63. 用途の増加: ネイティブ相互運用 • Xamarin統合で対応プラットフォームが増加 • ネイティブ相互運用が大変になったらしい • C#にもいくつか相互運用用の文法追加 • nint, nuint: CPUネイティブなint • 関数ポインター (delegate* <int, void> みたいなの) • 間接的なメリット(ほとんどの人は直接使わない) • dotnet/runtime内で使われまくる予定 • 全.NETユーザーが間接的に恩恵受ける
    64. 64. まとめ • .NET 5.0 • 年次リリース化&用途増加 • C# 9.0 • 大きな機能は少しずつ改善 • レコード型、パターン マッチング、Nullability解析 • 用途増加に対応 • top-levelプログラム、source generator

    Editor's Notes

  • https://github.com/dotnet/roslyn/blob/master/docs/Language%20Feature%20Status.md
  • newの有無とか、()の有無とかで細かい不整合は残ってたりするんだけど…
  • https://docs.microsoft.com/en-us/dotnet/csharp/tutorials/
  • https://devblogs.microsoft.com/dotnet/net-interactive-preview-3-vs-code-insiders-and-polyglot-notebooks/
  • More Related Content

    Related Books

    Free with a 30 day trial from Scribd

    See all

    Related Audiobooks

    Free with a 30 day trial from Scribd

    See all

    ×