$30 off During Our Annual Pro Sale. View Details »

Roslyn とその活用法

neno
September 24, 2022

Roslyn とその活用法

.NET ラボ 2022/09/24 での発表資料

GitHub
- Tapper
- TypedSignalR.Client
- TypedSignalR.Client.TypeScript
Twitter
Blog
neno.dev

neno

September 24, 2022
Tweet

More Decks by neno

Other Decks in Technology

Transcript

  1. Roslyn とその活用法 .NET ラボ 2022/09/24 何縫ねの。

  2. 自己紹介 1 • 所属: NTTコミュニケーションズ イノベーションセンター • 趣味: C#, OSS,

    ドール, 一眼(α7 IV) 何縫ねの。 nenoNaninu nenoMake ブログ https://blog.neno.dev その他 https://neno.dev
  3. Roslyn 2

  4. Roslyn 3 • .NET Compiler Platform • Compiler as a

    Service • C#で書かれた、C#コンパイラ • Compiler API が生えている。 https://github.com/dotnet/roslyn Roslyn C# の観点からみれば
  5. Roslyn 4 Compiler API ?

  6. Roslyn 5 コンパイラのお仕事 字句解析 構文解析 意味解析 コード生成

  7. Roslyn 6 コンパイラのお仕事 字句解析 構文解析 意味解析 コード生成

  8. Roslyn 7 コンパイラのお仕事 字句解析 構文解析 意味解析 コード生成

  9. Roslyn 8 コンパイラのお仕事 字句解析 構文解析 意味解析 コード生成

  10. Roslyn 9 コンパイラのお仕事 字句解析 構文解析 意味解析 コード生成

  11. Roslyn 10 コンパイラのお仕事 字句解析 構文解析 意味解析 コード生成

  12. Roslyn 11 コンパイラのお仕事 字句解析 構文解析 意味解析 コード生成 構文解析時点では、 intという文字列

  13. Roslyn 12 コンパイラのお仕事 字句解析 構文解析 意味解析 コード生成 文字列ではなく、 intという”型”である意味を解析 構文解析時点では、

    intという文字列
  14. Roslyn 13 コンパイラのお仕事 字句解析 構文解析 意味解析 コード生成 MSILを出力

  15. Roslyn 14 字句解析 構文解析 意味解析 コード生成 Compiler API コンパイラのお仕事

  16. Roslyn 15 なにが嬉しいの?

  17. Roslyn 16 ソースコードを入力とした プログラムが作れる

  18. • Source Generator • Analyzer • Console App Roslyn 17

    Compiler APIを通して出来る事。
  19. Roslyn 18 Compiler APIを通して出来る事。 • Source Generator • Analyzer •

    Console App
  20. • Source Generator • Analyzer • Console App Roslyn 19

    Compiler APIを通して出来る事。 Roslyn 組み込みの機能
  21. • Source Generator • Analyzer • Console App Roslyn 20

    Compiler APIを通して出来る事。 Roslyn 組み込みの機能 Roslyn を普通の ライブラリとして使用
  22. • Source Generator • Analyzer • Console App Roslyn 21

    Compiler APIを通して出来る事。 Roslyn 組み込みの機能 Roslyn を普通の ライブラリとして使用 活用例(OSS)と共に紹介
  23. • Source Generator • Analyzer • Console App Roslyn 22

    Compiler APIを通して出来る事。 Roslyn 組み込みの機能 Roslyn を普通の ライブラリとして使用 活用例(OSS)と共に紹介
  24. Roslyn : Console App 23 Server (C#) Client (TypeScript) https://blog.neno.dev/entry/2022/03/31/213837

  25. Roslyn : Console App 24 Server (C#) Client (TypeScript) https://blog.neno.dev/entry/2022/03/31/213837

  26. Roslyn : Console App 25 Server (C#) Client (TypeScript) JSON

    https://blog.neno.dev/entry/2022/03/31/213837
  27. Roslyn : Console App 26 Server (C#) Client (TypeScript) JSON

    https://blog.neno.dev/entry/2022/03/31/213837
  28. Roslyn : Console App 27 Server (C#) Client (TypeScript) JSON

    https://blog.neno.dev/entry/2022/03/31/213837 両方手書き?
  29. Roslyn : Console App 28 Server (C#) Client (TypeScript) JSON

    Server側を変更したらClient側は コンパイルエラー吐いて欲しい https://blog.neno.dev/entry/2022/03/31/213837 両方手書き?
  30. Roslyn : Console App 29 JSON 両方手書き? Server (C#) Client

    (TypeScript) https://blog.neno.dev/entry/2022/03/31/213837 Server側を変更したらClient側は コンパイルエラー吐いて欲しい
  31. Roslyn : Console App 30 JSON 両方手書き? Client (TypeScript) Server

    (C#) https://blog.neno.dev/entry/2022/03/31/213837 Server側を変更したらClient側は コンパイルエラー吐いて欲しい
  32. Roslyn : Console App 31 JSON Client (TypeScript) Server (C#)

  33. Roslyn : Console App 32 JSON C#からTypeScriptに トランスパイルできればいいのでは? Server (C#)

    Client (TypeScript)
  34. Roslyn 33 つくりました

  35. Roslyn 34 Roslyn を活用して!

  36. Roslyn : Console App 35 • C#の型定義からTypeScriptの型定義を 生成するConsole App •

    Roslynで意味解析まで行い、対象の型の 名前、メンバの型/名前等を 読み取ってTypeScriptコードを生成。 • シリアライザによって生成する型を 適切に調整 $ tapper --project path/to/Xxx.csproj --output generated https://github.com/nenoNaninu/Tapper Tapper
  37. Roslyn : Console App 36 • C#の型定義からTypeScriptの型定義を 生成するConsole App •

    Roslynで意味解析まで行い、対象の型の 名前、メンバの型/名前等を 読み取ってTypeScriptコードを生成。 • シリアライザによって生成する型を 適切に調整 $ tapper --project path/to/Xxx.csproj --output generated https://github.com/nenoNaninu/Tapper Tapper Attributeをアノテーションするだけ
  38. Roslyn : Console App 37 • C#の型定義からTypeScriptの型定義を 生成するConsole App •

    Roslynで意味解析まで行い、対象の型の 名前、メンバの型/名前等を 読み取ってTypeScriptコードを生成。 • シリアライザによって生成する型を 適切に調整 $ tapper --project path/to/Xxx.csproj --output generated https://github.com/nenoNaninu/Tapper Tapper Attributeをアノテーションするだけ JSON/MsgPack 対応
  39. Roslyn : Console App 38 • C#の型定義からTypeScriptの型定義を 生成するConsole App •

    Roslynで意味解析まで行い、対象の型の 名前、メンバの型/名前等を 読み取ってTypeScriptコードを生成。 • シリアライザによって生成する型を 適切に調整 $ tapper --project path/to/Xxx.csproj --output generated https://github.com/nenoNaninu/Tapper Tapper Attributeをアノテーションするだけ 1コマンド! JSON/MsgPack 対応
  40. Roslyn : Console App 39 Tapper

  41. Roslyn : Console App 40 詳細な JSDoc どの C# 型由来か一目瞭然

    Tapper
  42. Roslyn : Console App 41 詳細な JSDoc どの C# 型由来か一目瞭然

    Tapper TypeScript での number が int か float かで迷わない!
  43. Roslyn : Console App 42 • ユーザー定義型がネストしたら? Tapper https://github.com/nenoNaninu/Tapper

  44. Roslyn : Console App 43 • ユーザー定義型がネストしたら? Tapper https://github.com/nenoNaninu/Tapper Attributeがアノテーション

    されてる型の中で ユーザ定義型が使われている
  45. Roslyn : Console App 44 • ユーザー定義型がネストしたら? Tapper https://github.com/nenoNaninu/Tapper Attributeがアノテーション

    されてる型の中で ユーザ定義型が使われている 中で使われる型にも Attributeを アノテーションする 必要がある
  46. Roslyn : Console App 45 • ユーザー定義型がネストしたら? Tapper https://github.com/nenoNaninu/Tapper Attributeがアノテーション

    されてる型の中で ユーザ定義型が使われている 中で使われる型にも Attributeを アノテーションする 必要がある Attributeなので コンパイル時に 制約出来ない。 →ランタイムエラー?
  47. • Source Generator • Analyzer • Console App Roslyn 46

    Compiler APIを通して出来る事。
  48. • Source Generator • Analyzer • Console App Roslyn 47

    Compiler APIを通して出来る事。
  49. Roslyn: Analyzer 48 Attribute を アノテーションするのが 正しい使い方

  50. Roslyn: Analyzer 49 Attribute を アノテーションするのが 正しい使い方

  51. Roslyn: Analyzer 50 Attribute を アノテーションするのが 正しい使い方 メンバの型に Attribute が付いてないぞ~

    と教えてくれる
  52. Roslyn: Analyzer 51 Attribute を アノテーションするのが 正しい使い方 メンバの型に Attribute が付いてないぞ~

    と教えてくれる CLI で実行時エラー! みたいな状況を防げる
  53. • Source Generator • Analyzer • Console App Roslyn 52

    Compiler APIを通して出来る事。
  54. • Source Generator • Analyzer • Console App Roslyn 53

    Compiler APIを通して出来る事。
  55. Roslyn: Source Generator 54 字句解析 構文解析 意味解析 コード生成 Source Generator

    とは
  56. Roslyn: Source Generator 55 字句解析 構文解析 意味解析 コード生成 Source Generator

    とは Compilation を取得
  57. Roslyn: Source Generator 56 字句解析 構文解析 意味解析 コード生成 Source Generator

    とは Compilation を取得 構文木/意味モデルなどが 全て含まれている
  58. Roslyn: Source Generator 57 字句解析 構文解析 意味解析 コード生成 Source Generator

    とは https://learn.microsoft.com/en-us/dotnet/csharp/roslyn-sdk/source-generators-overview Compilation を取得 構文木/意味モデルなどが 全て含まれている
  59. Roslyn: Source Generator 58 字句解析 構文解析 意味解析 コード生成 Source Generator

    とは Compilation を取得 https://learn.microsoft.com/en-us/dotnet/csharp/roslyn-sdk/source-generators-overview 動的コード生成 IL Generator Expression Tree (Reflection) 構文木/意味モデルなどが 全て含まれている
  60. Roslyn: Source Generator 59 字句解析 構文解析 意味解析 コード生成 Source Generator

    とは Compilation を取得 https://learn.microsoft.com/en-us/dotnet/csharp/roslyn-sdk/source-generators-overview 構文木/意味モデルなどが 全て含まれている 8割くらいは Source Generator で代替 動的コード生成 IL Generator Expression Tree (Reflection)
  61. Roslyn: Source Generator 60 • interface ISourceGenerator • 全ソースコードを探索 →

    必要箇所を収集 → コード生成 .NET 5 .NET 6 • interface IIncrementalGenerator • ソースコードの変更を検知 → 変更箇所が必要箇所か検査 → 必要箇所だった場合のみ コード生成のロジックが発火
  62. Roslyn: Source Generator 61 • interface ISourceGenerator • 全ソースコードを探索 →

    必要箇所を収集 → コード生成 .NET 5 .NET 6 • interface IIncrementalGenerator • ソースコードの変更を検知 → 変更箇所が必要箇所か検査 → 必要箇所だった場合のみ コード生成のロジックが発火 IDE で一文字変更毎に 全ソース探索/コード生成が実行され 開発体験が厳しかった
  63. Roslyn: Source Generator 62 • interface ISourceGenerator • 全ソースコードを探索 →

    必要箇所を収集 → コード生成 .NET 5 .NET 6 • interface IIncrementalGenerator • ソースコードの変更を検知 → 変更箇所が必要箇所か検査 → 必要箇所だった場合のみ コード生成のロジックが発火 IDE で一文字変更毎に 全ソース探索/コード生成が実行され 開発体験が厳しかった IDE フレンドリー! 書き心地も向上!
  64. Roslyn: Source Generator 63 • IIncrementalGenerator

  65. Roslyn: Source Generator 64 • IIncrementalGenerator ①変更箇所のコード生成に必要かの検証 ②実際にコード生成するための処理 のパイプラインを Rx

    ライクに記述
  66. Roslyn: Source Generator 65 • IIncrementalGenerator ①変更箇所のコード生成に必要かの検証 ②実際にコード生成するための処理 のパイプラインを Rx

    ライクに記述 詳細は後述
  67. Roslyn: Source Generator 66 • 双方向のリアルタイム通信機能を提供する RPC ライブラリ • WebSocket

    が繋がらなくても大丈夫! • .NET Core移行時に実装を大幅に改良、現在も機能追加がされ続けている。 • 認証認可が .NET Core 3.1 で組み込まれたり。.NET 7 でも新機能が予定されてる。 • ASP.NET Core 組み込み。 • リポジトリ的にも ASP.NET Core の中。 • Blazor Server とかでも使われている。 SignalR とは https://github.com/dotnet/aspnetcore/tree/main/src/SignalR
  68. Roslyn: Source Generator 67 • Hubの method をinvokeする際 / Client

    の method を登録をする際、 • ①method 指定が文字列で辛い。 • ②引数/返り値の型を手動で与える必要があり辛い。 SignalR の問題点 https://github.com/dotnet/aspnetcore/tree/main/src/SignalR
  69. Roslyn: Source Generator 68 SignalR の問題点 https://github.com/dotnet/aspnetcore/tree/main/src/SignalR タイポ怖い 変更に追従させるの大変 •

    Hubの method をinvokeする際 / Client の method を登録をする際、 • ①method 指定が文字列で辛い。 • ②引数/返り値の型を手動で与える必要があり辛い。
  70. Roslyn: Source Generator 69 SignalR の問題点 https://github.com/dotnet/aspnetcore/tree/main/src/SignalR タイポ怖い 変更に追従させるの大変 Source

    Generator を活用して解決! • Hubの method をinvokeする際 / Client の method を登録をする際、 • ①method 指定が文字列で辛い。 • ②引数/返り値の型を手動で与える必要があり辛い。
  71. Roslyn: Source Generator 70 TypedSignalR.Client https://github.com/nenoNaninu/TypedSignalR.Client

  72. Roslyn: Source Generator 71 TypedSignalR.Client server 側は interface で 強く型付け出来る。

    一方 client 側は… https://github.com/nenoNaninu/TypedSignalR.Client
  73. Roslyn: Source Generator 72 TypedSignalR.Client Before https://github.com/nenoNaninu/TypedSignalR.Client server 側は interface

    で 強く型付け出来る。 一方 client 側は…
  74. Roslyn: Source Generator 73 TypedSignalR.Client Before https://github.com/nenoNaninu/TypedSignalR.Client server 側は interface

    で 強く型付け出来る。 一方 client 側は…
  75. Roslyn: Source Generator 74 TypedSignalR.Client Before After https://github.com/nenoNaninu/TypedSignalR.Client server 側は

    interface で 強く型付け出来る。 一方 client 側は…
  76. Roslyn: Source Generator 75 TypedSignalR.Client Before After https://github.com/nenoNaninu/TypedSignalR.Client 型引数に渡された interface

    を 実装した class を内部で生成 server 側は interface で 強く型付け出来る。 一方 client 側は…
  77. Roslyn: Source Generator 76 TypedSignalR.Client Before After 型引数に渡された interface で

    定義されている全methodを connection に bind する コードを内部で生成 https://github.com/nenoNaninu/TypedSignalR.Client 型引数に渡された interface を 実装した class を内部で生成 server 側は interface で 強く型付け出来る。 一方 client 側は…
  78. Roslyn: Source Generator 77 • 仕様に従ってない場合 • 型引数に interface 以外を渡している

    • interfaceに property, 不正な返り値/引数のmethod 等 TypedSignalR.Client コンパイルエラー! 詳細なエラーメッセージ ライブラリの仕様を知らなくても正しく使える! さらば ランタイムエラー!
  79. Roslyn: Source Generator 78 https://github.com/nenoNaninu/TypedSignalR.Client/blob/v3.1.1/src/TypedSignalR.Client/SourceGenerator.cs

  80. Roslyn: Source Generator 79 https://github.com/nenoNaninu/TypedSignalR.Client/blob/v3.1.1/src/TypedSignalR.Client/SourceGenerator.cs 事前に必要なコードを一度だけ生成 TypedSignalR.Client の場合は 拡張メソッドなど

  81. Roslyn: Source Generator 80 事前に必要なコードを一度だけ生成 TypedSignalR.Client の場合は 拡張メソッドなど 変更箇所に対する検証/整形などの パイプラインを

    Rx ライクに記述 https://github.com/nenoNaninu/TypedSignalR.Client/blob/v3.1.1/src/TypedSignalR.Client/SourceGenerator.cs
  82. Roslyn: Source Generator 81 事前に必要なコードを一度だけ生成 TypedSignalR.Client の場合は 拡張メソッドなど 変更箇所に対する検証/整形などの パイプラインを

    Rx ライクに記述 https://github.com/nenoNaninu/TypedSignalR.Client/blob/v3.1.1/src/TypedSignalR.Client/SourceGenerator.cs 構築したパイプラインを使って コードを生成/登録
  83. Roslyn 82 TypedSignalR.Client C# の SignalR client のためのもの

  84. Roslyn 83 TypeScript 版も欲しい

  85. Roslyn: Console App + Code Analyzer 84 • C#のinterfaceを解析 →

    TypeScriptで強く型付けされた SignalR clientを提供 TypedSignalR.Client.TypeScript $ dotnet tsrts --project path/to/Xxx.csproj --output generated https://github.com/nenoNaninu/TypedSignalR.Client.TypeScript
  86. Roslyn: Console App + Code Analyzer 85 • C#のinterfaceを解析 →

    TypeScriptで強く型付けされた SignalR clientを提供 TypedSignalR.Client.TypeScript $ dotnet tsrts --project path/to/Xxx.csproj --output generated https://github.com/nenoNaninu/TypedSignalR.Client.TypeScript Attribute を アノテーションするだけ Attribute を アノテーションするだけ
  87. Roslyn: Console App + Code Analyzer 86 • C#のinterfaceを解析 →

    TypeScriptで強く型付けされた SignalR clientを提供 TypedSignalR.Client.TypeScript $ dotnet tsrts --project path/to/Xxx.csproj --output generated https://github.com/nenoNaninu/TypedSignalR.Client.TypeScript Attribute を アノテーションするだけ Attribute を アノテーションするだけ 1 コマンド!
  88. Roslyn: Console App + Code Analyzer 87 TypedSignalR.Client.TypeScript Before

  89. Roslyn: Console App + Code Analyzer 88 TypedSignalR.Client.TypeScript Before After

  90. Roslyn: Console App + Code Analyzer 89 TypedSignalR.Client.TypeScript Before After

  91. Roslyn: Console App + Code Analyzer 90 TypedSignalR.Client.TypeScript Before After

    型指定さえすれば テンプレートはエディタ が吐き出してくれる
  92. Roslyn: Console App + Code Analyzer 91 TypedSignalR.Client.TypeScript Before After

    型指定さえすれば テンプレートはエディタ が吐き出してくれる 文字列 つかってるじゃん?
  93. Roslyn: Console App + Code Analyzer 92 TypedSignalR.Client.TypeScript Before After

    文字列 つかってるじゃん?
  94. Roslyn: Console App + Code Analyzer 93 TypedSignalR.Client.TypeScript Before After

    文字列 つかってるじゃん? string literal type で overload してるので大丈夫。 Intellisense もバッチリ
  95. Roslyn: Console App + Code Analyzer 94 メソッド定義に Tapper の

    Attribute が付いてない型を 使っていた場合に警告 https://github.com/nenoNaninu/TypedSignalR.Client.TypeScript#analyzer TypedSignalR.Client.TypeScript は Tapper 内蔵してこれを解決 SignalR の hub/receiver method で ユーザ定義型を使いたい
  96. まとめ 95 • Source Generator • C# コードを解析してC# コードを生成!以下の要望をストレートに解決! •

    動的コード生成しないと厳しいな~ • ボイラーコード大量に発生するな~ • Analyzer • 型で制約できない事はAnalyzerで制約!リアルタイムに発見! • Tapperのように外部ツール都合のAttributeの使い方を矯正 • このAPI使うな!この返り値を捨てるな!とか、使い道はいろいろ。 • 頑張れば code fix も • Console App • C# コードと連携する他言語(TypeScript等)をより快適に! • ぶっちゃけなんでもできます!やりたい放題! Roslyn を使う事で C# コードを入力として、アレコレ出来る!