-
Notifications
You must be signed in to change notification settings - Fork 0
JA 01_faq_and_rationale
🇺🇸 English | 🇯🇵 日本語 | Introduction
本章では、ゼロアロケーションを実現する v4 ジェネレーターのアーキテクチャ上の設計哲学について解説するとともに、API設計やコード合成、最新の .NET 機能との統合に関するよくある質問に回答します。
.NET MAUI や WPF、WinUI、Avalonia などの XAML フレームワークにおいて、DependencyProperty の記述は非常に冗長になることで知られています。DependencyPropertyGenerator の最大の目的は、大規模なプロジェクトであっても IDE のレスポンスを低下させることなく、冗長な定型コードであるボイラープレートを撲滅することです。
高スループットかつゼロアロケーションなコード生成を実現するため、v4 のパイプラインでは以下の積極的なアーキテクチャ変更を取り入れています。
ジェネレーターは NormalizeWhitespace() の呼び出しや手動でのインデント処理を完全に廃止し、すべて左詰めのフラットなコードを出力します。
- パフォーマンスの向上: ホットパスにおいて、数千に及ぶインデント用の空白文字列のアロケーションを排除します。
- AI / LLM への親和性: Gemini Flash のような軽量な AI モデルは、コードを予測する際に空白のインデントをハルシネーションとして出力したり、ずらしてしまうことがよくあります。フラットな出力にすることで、フォーマットに依存しない決定的かつ安定したコード生成が可能になります。
コード合成において SyntaxFactory による抽象構文木である AST の再構築や変異を厳格に避けています。クラス定義を生成したり、new() を明示的な型へ変換するような動的な DefaultValueExpression を解決したりする際、解析済みの AST から直接トークンを抽出し、自作の SourceWriter へ直接ストリーミングします。
- Gen2 アロケーションのゼロ化: AST ノードの新規構築を完全にバイパスすることで、Gen2 ガベージコレクションのスパイクを未然に防ぎます。
コード生成のロジックは、スタックに割り当てられる SourceWriter および ClassScope ラッパーの上で動作します。これにより、文字列を組み立てる際のヒープアロケーションを完全に回避しています。
Note
トークンストリーミングの詳細なコード仕様、SourceWriter / ClassScope の実装規約、および AST Mutation 比較のマイクロベンチマーク測定結果については、05. コード生成とパフォーマンス最適化 を参照してください。
「Write Once, Run on Any XAML Platform(一度書けば、どの XAML プラットフォームでも動く)」 を実現するためです。
データ抽出フェーズを純粋な DTO に隔離し、出力をプラットフォーム固有の Strategy に委譲することで、全く同じ [DependencyProperty] 属性から DependencyProperty.Register (WPF)、AvaloniaProperty.Register (Avalonia)、BindableProperty.Create (MAUI) を自動で出し分けることができます。これにより、マルチプラットフォーム向け OSS ライブラリ作者や、フレームワーク移行中の企業チームにおける #if のボイラープレート地獄を解消します。
Avalonia 12.2 で公式のジェネレーターが登場した際は、その仕様と普及状況を評価します。
公式ジェネレーターはプラットフォーム固有の最適化に優れますが、「WPF や MAUI とコードベースを共有するための単一属性」としての需要がある限り、本ライブラリは AvaloniaFrameworkGenerator を維持します。コミュニティが完全に公式へ移行し、マルチターゲットの需要が消滅したと判断できた場合にのみ、段階的な非推奨化を検討します。
クラスレベルの属性は、通常の Dependency Property と、明確なバッキングフィールドにマッピングしづらい Attached Property の両方を宣言する上で、統一されたメンタルモデルを提供できるためです。ただし、C# 13 の partial property サポートもすでにネイティブ実装されており、背後にある同じ AST 解析ロジックを利用してクラスレベルの属性とシームレスに共存できるようになっています。
いいえ、損なわれません。生成されたコードのフォーマットは本来 IDE やフォーマッタの責任領域です。単なる見た目のためだけに、ジェネレーターのホットパス上で打鍵のたびに数メガバイトもの空白文字列をアロケーションするのは非常に非効率です。
もしデバッグ目的で生成ファイルを読む必要がある場合は、IDE のフォーマット機能を利用すれば瞬時にインデントされます。さらに、#line ディレクティブが埋め込まれているため、スタックトレースやコンパイルエラーは常に元のソースファイルへ正確にマッピングされます。
規約ベースの partial メソッドを通じて解決します。例えば partial void CoerceIsActive(ref bool value) や partial bool ValidateIsActive(bool value) といったメソッドを定義しておけば、ジェネレーターがそれを自動検知し、適切なメタデータコールバックとして配線します。また、AffectsRender = true や BindsTwoWayByDefault のような各フレームワーク特有のフラグは、属性の引数として宣言するだけで適用されます。
独自に実装した AST トークン抽出から文字列組み立て、そして SourceWriter のバッファリングに至る内部の合成パイプラインにおけるアロケーションは厳密に 0 Bytes です。残りの 2.22 MB は、Roslyn の API 境界で発生する避けられないオーバーヘッドです。具体的には、インクリメンタルパイプラインのキャッシュオーバーヘッド、GeneratorInitializationContext のセットアップ、そして生成したコードをコンパイラホストに渡す際の最終的な SourceText 文字列のアロケーションによるものです。ジェネレーターのコアロジック自体は完全にゼロアロケーションを維持しています。
エンドツーエンドのベンチマーク測定結果と詳細な削減比率については、05. コード生成とパフォーマンス最適化の Ⅵ. パフォーマンス指標 を参照してください。
壊れません。このジェネレーターは、実行時のリフレクションや Reflection.Emit を一切使わず、完全に標準的で静的な C# コードを出力します。したがって、NativeAOT や Trimming に対して 100% 安全です。コンパイル時に静的フィールドとプロパティラッパーを生成する仕組みのため、XAML Hot Reload や Language Server Protocol とも完璧に連動し、手書きのコードと全く同じように動作します。
This wiki is automatically synchronized from spec/ in the repository.
- Introduction
- 01. FAQ & Design Rationale
- 02. Foundation & Domain
- 03. Pipeline Architecture
- 04. Framework Strategies
- 05. Synthesis & Performance
- 06. Complexity Model
- 07. Test Specification
- 08. Diagnostics Reference
- 概要
- 01. 設計思想とFAQ
- 02. 基盤とドメイン
- 03. パイプライン構造
- 04. フレームワーク別生成仕様
- 05. コード生成と最適化
- 06. 計算量モデル
- 07. テスト仕様書
- 08. 診断機能リファレンス