Link
Embed
Share
Beginning
This slide
Copy link URL
Copy link URL
Copy iframe embed code
Copy iframe embed code
Copy javascript embed code
Copy javascript embed code
Share
Tweet
Share
Tweet
Slide 1
Slide 1 text
Roslyn とその活用法 .NET ラボ 2022/09/24 何縫ねの。
Slide 2
Slide 2 text
自己紹介 1 • 所属: NTTコミュニケーションズ イノベーションセンター • 趣味: C#, OSS, ドール, 一眼(α7 IV) 何縫ねの。 nenoNaninu nenoMake ブログ https://blog.neno.dev その他 https://neno.dev
Slide 3
Slide 3 text
Roslyn 2
Slide 4
Slide 4 text
Roslyn 3 • .NET Compiler Platform • Compiler as a Service • C#で書かれた、C#コンパイラ • Compiler API が生えている。 https://github.com/dotnet/roslyn Roslyn C# の観点からみれば
Slide 5
Slide 5 text
Roslyn 4 Compiler API ?
Slide 6
Slide 6 text
Roslyn 5 コンパイラのお仕事 字句解析 構文解析 意味解析 コード生成
Slide 7
Slide 7 text
Roslyn 6 コンパイラのお仕事 字句解析 構文解析 意味解析 コード生成
Slide 8
Slide 8 text
Roslyn 7 コンパイラのお仕事 字句解析 構文解析 意味解析 コード生成
Slide 9
Slide 9 text
Roslyn 8 コンパイラのお仕事 字句解析 構文解析 意味解析 コード生成
Slide 10
Slide 10 text
Roslyn 9 コンパイラのお仕事 字句解析 構文解析 意味解析 コード生成
Slide 11
Slide 11 text
Roslyn 10 コンパイラのお仕事 字句解析 構文解析 意味解析 コード生成
Slide 12
Slide 12 text
Roslyn 11 コンパイラのお仕事 字句解析 構文解析 意味解析 コード生成 構文解析時点では、 intという文字列
Slide 13
Slide 13 text
Roslyn 12 コンパイラのお仕事 字句解析 構文解析 意味解析 コード生成 文字列ではなく、 intという”型”である意味を解析 構文解析時点では、 intという文字列
Slide 14
Slide 14 text
Roslyn 13 コンパイラのお仕事 字句解析 構文解析 意味解析 コード生成 MSILを出力
Slide 15
Slide 15 text
Roslyn 14 字句解析 構文解析 意味解析 コード生成 Compiler API コンパイラのお仕事
Slide 16
Slide 16 text
Roslyn 15 なにが嬉しいの?
Slide 17
Slide 17 text
Roslyn 16 ソースコードを入力とした プログラムが作れる
Slide 18
Slide 18 text
• Source Generator • Analyzer • Console App Roslyn 17 Compiler APIを通して出来る事。
Slide 19
Slide 19 text
Roslyn 18 Compiler APIを通して出来る事。 • Source Generator • Analyzer • Console App
Slide 20
Slide 20 text
• Source Generator • Analyzer • Console App Roslyn 19 Compiler APIを通して出来る事。 Roslyn 組み込みの機能
Slide 21
Slide 21 text
• Source Generator • Analyzer • Console App Roslyn 20 Compiler APIを通して出来る事。 Roslyn 組み込みの機能 Roslyn を普通の ライブラリとして使用
Slide 22
Slide 22 text
• Source Generator • Analyzer • Console App Roslyn 21 Compiler APIを通して出来る事。 Roslyn 組み込みの機能 Roslyn を普通の ライブラリとして使用 活用例(OSS)と共に紹介
Slide 23
Slide 23 text
• Source Generator • Analyzer • Console App Roslyn 22 Compiler APIを通して出来る事。 Roslyn 組み込みの機能 Roslyn を普通の ライブラリとして使用 活用例(OSS)と共に紹介
Slide 24
Slide 24 text
Roslyn : Console App 23 Server (C#) Client (TypeScript) https://blog.neno.dev/entry/2022/03/31/213837
Slide 25
Slide 25 text
Roslyn : Console App 24 Server (C#) Client (TypeScript) https://blog.neno.dev/entry/2022/03/31/213837
Slide 26
Slide 26 text
Roslyn : Console App 25 Server (C#) Client (TypeScript) JSON https://blog.neno.dev/entry/2022/03/31/213837
Slide 27
Slide 27 text
Roslyn : Console App 26 Server (C#) Client (TypeScript) JSON https://blog.neno.dev/entry/2022/03/31/213837
Slide 28
Slide 28 text
Roslyn : Console App 27 Server (C#) Client (TypeScript) JSON https://blog.neno.dev/entry/2022/03/31/213837 両方手書き?
Slide 29
Slide 29 text
Roslyn : Console App 28 Server (C#) Client (TypeScript) JSON Server側を変更したらClient側は コンパイルエラー吐いて欲しい https://blog.neno.dev/entry/2022/03/31/213837 両方手書き?
Slide 30
Slide 30 text
Roslyn : Console App 29 JSON 両方手書き? Server (C#) Client (TypeScript) https://blog.neno.dev/entry/2022/03/31/213837 Server側を変更したらClient側は コンパイルエラー吐いて欲しい
Slide 31
Slide 31 text
Roslyn : Console App 30 JSON 両方手書き? Client (TypeScript) Server (C#) https://blog.neno.dev/entry/2022/03/31/213837 Server側を変更したらClient側は コンパイルエラー吐いて欲しい
Slide 32
Slide 32 text
Roslyn : Console App 31 JSON Client (TypeScript) Server (C#)
Slide 33
Slide 33 text
Roslyn : Console App 32 JSON C#からTypeScriptに トランスパイルできればいいのでは? Server (C#) Client (TypeScript)
Slide 34
Slide 34 text
Roslyn 33 つくりました
Slide 35
Slide 35 text
Roslyn 34 Roslyn を活用して!
Slide 36
Slide 36 text
Roslyn : Console App 35 • C#の型定義からTypeScriptの型定義を 生成するConsole App • Roslynで意味解析まで行い、対象の型の 名前、メンバの型/名前等を 読み取ってTypeScriptコードを生成。 • シリアライザによって生成する型を 適切に調整 $ tapper --project path/to/Xxx.csproj --output generated https://github.com/nenoNaninu/Tapper Tapper
Slide 37
Slide 37 text
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をアノテーションするだけ
Slide 38
Slide 38 text
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 対応
Slide 39
Slide 39 text
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 対応
Slide 40
Slide 40 text
Roslyn : Console App 39 Tapper
Slide 41
Slide 41 text
Roslyn : Console App 40 詳細な JSDoc どの C# 型由来か一目瞭然 Tapper
Slide 42
Slide 42 text
Roslyn : Console App 41 詳細な JSDoc どの C# 型由来か一目瞭然 Tapper TypeScript での number が int か float かで迷わない!
Slide 43
Slide 43 text
Roslyn : Console App 42 • ユーザー定義型がネストしたら? Tapper https://github.com/nenoNaninu/Tapper
Slide 44
Slide 44 text
Roslyn : Console App 43 • ユーザー定義型がネストしたら? Tapper https://github.com/nenoNaninu/Tapper Attributeがアノテーション されてる型の中で ユーザ定義型が使われている
Slide 45
Slide 45 text
Roslyn : Console App 44 • ユーザー定義型がネストしたら? Tapper https://github.com/nenoNaninu/Tapper Attributeがアノテーション されてる型の中で ユーザ定義型が使われている 中で使われる型にも Attributeを アノテーションする 必要がある
Slide 46
Slide 46 text
Roslyn : Console App 45 • ユーザー定義型がネストしたら? Tapper https://github.com/nenoNaninu/Tapper Attributeがアノテーション されてる型の中で ユーザ定義型が使われている 中で使われる型にも Attributeを アノテーションする 必要がある Attributeなので コンパイル時に 制約出来ない。 →ランタイムエラー?
Slide 47
Slide 47 text
• Source Generator • Analyzer • Console App Roslyn 46 Compiler APIを通して出来る事。
Slide 48
Slide 48 text
• Source Generator • Analyzer • Console App Roslyn 47 Compiler APIを通して出来る事。
Slide 49
Slide 49 text
Roslyn: Analyzer 48 Attribute を アノテーションするのが 正しい使い方
Slide 50
Slide 50 text
Roslyn: Analyzer 49 Attribute を アノテーションするのが 正しい使い方
Slide 51
Slide 51 text
Roslyn: Analyzer 50 Attribute を アノテーションするのが 正しい使い方 メンバの型に Attribute が付いてないぞ~ と教えてくれる
Slide 52
Slide 52 text
Roslyn: Analyzer 51 Attribute を アノテーションするのが 正しい使い方 メンバの型に Attribute が付いてないぞ~ と教えてくれる CLI で実行時エラー! みたいな状況を防げる
Slide 53
Slide 53 text
• Source Generator • Analyzer • Console App Roslyn 52 Compiler APIを通して出来る事。
Slide 54
Slide 54 text
• Source Generator • Analyzer • Console App Roslyn 53 Compiler APIを通して出来る事。
Slide 55
Slide 55 text
Roslyn: Source Generator 54 字句解析 構文解析 意味解析 コード生成 Source Generator とは
Slide 56
Slide 56 text
Roslyn: Source Generator 55 字句解析 構文解析 意味解析 コード生成 Source Generator とは Compilation を取得
Slide 57
Slide 57 text
Roslyn: Source Generator 56 字句解析 構文解析 意味解析 コード生成 Source Generator とは Compilation を取得 構文木/意味モデルなどが 全て含まれている
Slide 58
Slide 58 text
Roslyn: Source Generator 57 字句解析 構文解析 意味解析 コード生成 Source Generator とは https://learn.microsoft.com/en-us/dotnet/csharp/roslyn-sdk/source-generators-overview Compilation を取得 構文木/意味モデルなどが 全て含まれている
Slide 59
Slide 59 text
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) 構文木/意味モデルなどが 全て含まれている
Slide 60
Slide 60 text
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)
Slide 61
Slide 61 text
Roslyn: Source Generator 60 • interface ISourceGenerator • 全ソースコードを探索 → 必要箇所を収集 → コード生成 .NET 5 .NET 6 • interface IIncrementalGenerator • ソースコードの変更を検知 → 変更箇所が必要箇所か検査 → 必要箇所だった場合のみ コード生成のロジックが発火
Slide 62
Slide 62 text
Roslyn: Source Generator 61 • interface ISourceGenerator • 全ソースコードを探索 → 必要箇所を収集 → コード生成 .NET 5 .NET 6 • interface IIncrementalGenerator • ソースコードの変更を検知 → 変更箇所が必要箇所か検査 → 必要箇所だった場合のみ コード生成のロジックが発火 IDE で一文字変更毎に 全ソース探索/コード生成が実行され 開発体験が厳しかった
Slide 63
Slide 63 text
Roslyn: Source Generator 62 • interface ISourceGenerator • 全ソースコードを探索 → 必要箇所を収集 → コード生成 .NET 5 .NET 6 • interface IIncrementalGenerator • ソースコードの変更を検知 → 変更箇所が必要箇所か検査 → 必要箇所だった場合のみ コード生成のロジックが発火 IDE で一文字変更毎に 全ソース探索/コード生成が実行され 開発体験が厳しかった IDE フレンドリー! 書き心地も向上!
Slide 64
Slide 64 text
Roslyn: Source Generator 63 • IIncrementalGenerator
Slide 65
Slide 65 text
Roslyn: Source Generator 64 • IIncrementalGenerator ①変更箇所のコード生成に必要かの検証 ②実際にコード生成するための処理 のパイプラインを Rx ライクに記述
Slide 66
Slide 66 text
Roslyn: Source Generator 65 • IIncrementalGenerator ①変更箇所のコード生成に必要かの検証 ②実際にコード生成するための処理 のパイプラインを Rx ライクに記述 詳細は後述
Slide 67
Slide 67 text
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
Slide 68
Slide 68 text
Roslyn: Source Generator 67 • Hubの method をinvokeする際 / Client の method を登録をする際、 • ①method 指定が文字列で辛い。 • ②引数/返り値の型を手動で与える必要があり辛い。 SignalR の問題点 https://github.com/dotnet/aspnetcore/tree/main/src/SignalR
Slide 69
Slide 69 text
Roslyn: Source Generator 68 SignalR の問題点 https://github.com/dotnet/aspnetcore/tree/main/src/SignalR タイポ怖い 変更に追従させるの大変 • Hubの method をinvokeする際 / Client の method を登録をする際、 • ①method 指定が文字列で辛い。 • ②引数/返り値の型を手動で与える必要があり辛い。
Slide 70
Slide 70 text
Roslyn: Source Generator 69 SignalR の問題点 https://github.com/dotnet/aspnetcore/tree/main/src/SignalR タイポ怖い 変更に追従させるの大変 Source Generator を活用して解決! • Hubの method をinvokeする際 / Client の method を登録をする際、 • ①method 指定が文字列で辛い。 • ②引数/返り値の型を手動で与える必要があり辛い。
Slide 71
Slide 71 text
Roslyn: Source Generator 70 TypedSignalR.Client https://github.com/nenoNaninu/TypedSignalR.Client
Slide 72
Slide 72 text
Roslyn: Source Generator 71 TypedSignalR.Client server 側は interface で 強く型付け出来る。 一方 client 側は… https://github.com/nenoNaninu/TypedSignalR.Client
Slide 73
Slide 73 text
Roslyn: Source Generator 72 TypedSignalR.Client Before https://github.com/nenoNaninu/TypedSignalR.Client server 側は interface で 強く型付け出来る。 一方 client 側は…
Slide 74
Slide 74 text
Roslyn: Source Generator 73 TypedSignalR.Client Before https://github.com/nenoNaninu/TypedSignalR.Client server 側は interface で 強く型付け出来る。 一方 client 側は…
Slide 75
Slide 75 text
Roslyn: Source Generator 74 TypedSignalR.Client Before After https://github.com/nenoNaninu/TypedSignalR.Client server 側は interface で 強く型付け出来る。 一方 client 側は…
Slide 76
Slide 76 text
Roslyn: Source Generator 75 TypedSignalR.Client Before After https://github.com/nenoNaninu/TypedSignalR.Client 型引数に渡された interface を 実装した class を内部で生成 server 側は interface で 強く型付け出来る。 一方 client 側は…
Slide 77
Slide 77 text
Roslyn: Source Generator 76 TypedSignalR.Client Before After 型引数に渡された interface で 定義されている全methodを connection に bind する コードを内部で生成 https://github.com/nenoNaninu/TypedSignalR.Client 型引数に渡された interface を 実装した class を内部で生成 server 側は interface で 強く型付け出来る。 一方 client 側は…
Slide 78
Slide 78 text
Roslyn: Source Generator 77 • 仕様に従ってない場合 • 型引数に interface 以外を渡している • interfaceに property, 不正な返り値/引数のmethod 等 TypedSignalR.Client コンパイルエラー! 詳細なエラーメッセージ ライブラリの仕様を知らなくても正しく使える! さらば ランタイムエラー!
Slide 79
Slide 79 text
Roslyn: Source Generator 78 https://github.com/nenoNaninu/TypedSignalR.Client/blob/v3.1.1/src/TypedSignalR.Client/SourceGenerator.cs
Slide 80
Slide 80 text
Roslyn: Source Generator 79 https://github.com/nenoNaninu/TypedSignalR.Client/blob/v3.1.1/src/TypedSignalR.Client/SourceGenerator.cs 事前に必要なコードを一度だけ生成 TypedSignalR.Client の場合は 拡張メソッドなど
Slide 81
Slide 81 text
Roslyn: Source Generator 80 事前に必要なコードを一度だけ生成 TypedSignalR.Client の場合は 拡張メソッドなど 変更箇所に対する検証/整形などの パイプラインを Rx ライクに記述 https://github.com/nenoNaninu/TypedSignalR.Client/blob/v3.1.1/src/TypedSignalR.Client/SourceGenerator.cs
Slide 82
Slide 82 text
Roslyn: Source Generator 81 事前に必要なコードを一度だけ生成 TypedSignalR.Client の場合は 拡張メソッドなど 変更箇所に対する検証/整形などの パイプラインを Rx ライクに記述 https://github.com/nenoNaninu/TypedSignalR.Client/blob/v3.1.1/src/TypedSignalR.Client/SourceGenerator.cs 構築したパイプラインを使って コードを生成/登録
Slide 83
Slide 83 text
Roslyn 82 TypedSignalR.Client C# の SignalR client のためのもの
Slide 84
Slide 84 text
Roslyn 83 TypeScript 版も欲しい
Slide 85
Slide 85 text
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
Slide 86
Slide 86 text
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 を アノテーションするだけ
Slide 87
Slide 87 text
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 コマンド!
Slide 88
Slide 88 text
Roslyn: Console App + Code Analyzer 87 TypedSignalR.Client.TypeScript Before
Slide 89
Slide 89 text
Roslyn: Console App + Code Analyzer 88 TypedSignalR.Client.TypeScript Before After
Slide 90
Slide 90 text
Roslyn: Console App + Code Analyzer 89 TypedSignalR.Client.TypeScript Before After
Slide 91
Slide 91 text
Roslyn: Console App + Code Analyzer 90 TypedSignalR.Client.TypeScript Before After 型指定さえすれば テンプレートはエディタ が吐き出してくれる
Slide 92
Slide 92 text
Roslyn: Console App + Code Analyzer 91 TypedSignalR.Client.TypeScript Before After 型指定さえすれば テンプレートはエディタ が吐き出してくれる 文字列 つかってるじゃん?
Slide 93
Slide 93 text
Roslyn: Console App + Code Analyzer 92 TypedSignalR.Client.TypeScript Before After 文字列 つかってるじゃん?
Slide 94
Slide 94 text
Roslyn: Console App + Code Analyzer 93 TypedSignalR.Client.TypeScript Before After 文字列 つかってるじゃん? string literal type で overload してるので大丈夫。 Intellisense もバッチリ
Slide 95
Slide 95 text
Roslyn: Console App + Code Analyzer 94 メソッド定義に Tapper の Attribute が付いてない型を 使っていた場合に警告 https://github.com/nenoNaninu/TypedSignalR.Client.TypeScript#analyzer TypedSignalR.Client.TypeScript は Tapper 内蔵してこれを解決 SignalR の hub/receiver method で ユーザ定義型を使いたい
Slide 96
Slide 96 text
まとめ 95 • Source Generator • C# コードを解析してC# コードを生成!以下の要望をストレートに解決! • 動的コード生成しないと厳しいな~ • ボイラーコード大量に発生するな~ • Analyzer • 型で制約できない事はAnalyzerで制約!リアルタイムに発見! • Tapperのように外部ツール都合のAttributeの使い方を矯正 • このAPI使うな!この返り値を捨てるな!とか、使い道はいろいろ。 • 頑張れば code fix も • Console App • C# コードと連携する他言語(TypeScript等)をより快適に! • ぶっちゃけなんでもできます!やりたい放題! Roslyn を使う事で C# コードを入力として、アレコレ出来る!