Webエンジニア向けプログラミング解説動画をYouTubeで配信中!
▶ チャンネル登録はこちら

【ITニュース解説】Writing simple C# source code generator with Fluent API

2025年10月02日に「Dev.to」が公開したITニュース「Writing simple C# source code generator with Fluent API」について初心者にもわかりやすく解説しています。

作成日: 更新日:

ITニュース概要

C#のRoslyn Source Generatorsは、開発時にコードを自動生成し、動的な処理を効率化する技術だ。リフレクションなど既存手法より高速で、IDE上でリアルタイム生成される。HamsterWheel.FluentCodeGeneratorsのようなFluent APIライブラリを使えば、複雑な生成ロジックやusing文の管理も簡潔に記述でき、効率的なC#開発を支援する。

ITニュース解説

C#を学ぶ皆さん、プログラムがプログラムのコードを自動で生成する「ソースコードジェネレーター」という技術を知っていますか。この技術は、効率的な開発やメンテナンス性の向上に大きく貢献します。ここでは、そのソースコードジェネレーターについて、基本的な考え方から具体的な利用方法、そして開発を助けるツールまでを解説します。

まず、なぜソースコードジェネレーターが必要とされるのかについて説明します。C#を含む多くのプログラミング言語では、特定の処理を自動化するために「ジェネリック」なコード、つまり汎用的な処理を書くことができます。例えば、アプリケーションに新しい機能を追加する際に、インターフェースを実装したクラスを自動的に登録したいといったケースが考えられます。このような場合、アプリケーションが実行されている最中に、プログラム自身がプロジェクト内のクラスを調べて登録する「リフレクション」という方法が一般的に使われます。しかし、リフレクションは実行時に多くの情報を調べ上げるため、処理に時間がかかり、アプリケーションの起動がわずかに遅くなる可能性があります。また、Fodyのようなツールを使ってコンパイル後にコードを書き換える方法もありますが、これは元のソースコードと実行されるコードが異なるため、デバッグ(プログラムの不具合を見つけて修正する作業)が難しくなるという課題がありました。

そこで登場するのがRoslyn Source Generators、つまりソースコードジェネレーターです。これは、コードを「書く」のではなく「生成する」ことで、これらの課題を解決する新しいアプローチです。プログラムがコンパイルされる前、または開発中に、特定のルールに基づいて新しいC#コードファイルを自動的に作成します。この生成されたコードは、通常のC#コードと同じように扱われるため、リフレクションのような実行時のオーバーヘッドがなく、Fodyのようなコード改変ツールに見られるデバッグの困難さもありません。開発者は、IDE(統合開発環境)でコードを記述している最中に、ジェネレーターがバックグラウンドで新しいコードを生成し、リアルタイムでエラーが解消されたり、新しい機能が追加されたりする様子を見ることができます。たとえば、プロジェクトに簡単なテキストファイルを追加するだけで、そのテキストファイルの内容をコンソールに出力するC#クラスが自動生成されるといったことが可能になります。

ソースコードジェネレーターを作成するには、いくつかの準備が必要です。まず、専用のC#プロジェクトを新規に作成します。このプロジェクトは、.NET Standard 2.0という特定のバージョンをターゲットにする必要があります。次に、プロジェクトファイルにいくつかの設定を追加して、このプロジェクトがRoslynコンポーネント、つまりソースコードジェネレーターとして機能することを明示します。具体的には、プロジェクトの設定ファイルに「IsRoslynComponent」という項目を「true」に設定します。また、Roslyn APIというコード生成を助ける機能を利用するために、「HamsterWheel.FluentCodeGenerators」のようなNuGetパッケージを追加します。このとき、ジェネレーターが必要とするこれらのパッケージが、生成されたジェネレーターのDLLファイルと一緒に正しく配置されるように、プロジェクトファイルに詳細な設定を行う必要があります。この設定が不十分だと、ジェネレーターが初期化される際に必要なファイルが見つからず、エラーが発生してしまうことがあるため、重要な手順です。

プロジェクトの準備が整ったら、いよいよジェネレーター本体のコードを書き始めます。ソースコードジェネレーターは、「IIncrementalGenerator」という特定のインターフェースを実装するクラスとして作成し、「Generator」という属性を付与します。このクラスの「Initialize」メソッドの中に、ジェネレーターのロジックを記述していきます。例えば、ジェネレーターが利用する特別な属性などを、プロジェクトのコンパイル前にあらかじめ生成したい場合は、「RegisterPostInitializationOutput」という機能を使って初期コードを追加できます。さらに、特定のファイル(例えば、拡張子が.txtの追加ファイル)を監視し、その内容に基づいてC#コードを生成したい場合は、「AdditionalTextsProvider」という機能を利用します。これにより、プロジェクトに追加されたファイルの中から特定の条件に合うものを抽出し、そのファイル名や内容といった情報を取得できます。そして、「RegisterSourceOutput」を使って、取得した情報から具体的なC#コードを文字列として組み立て、プロジェクトに追加します。

しかし、ここで課題が生じます。C#コードを単なる文字列として組み立てる場合、インデント(字下げ)の調整、適切な「using」ステートメント(名前空間のインポート)の追加、括弧の対応、セミコロンの忘れなど、考慮すべき点が非常に多くなります。特に、複数のクラスやメソッドを生成したり、複雑なロジックを共有したりする必要がある場合、文字列操作だけでは非常に読みにくく、メンテナンスしにくい「スパゲッティコード」になりがちです。

この課題を解決するために、「HamsterWheel.FluentCodeGenerators」のような「Fluent API」を提供するライブラリが役立ちます。Fluent APIを使うと、C#の構文を意識することなく、まるでC#のコードを記述しているかのように、メソッドチェーンを使ってクラス、メソッド、プロパティといったコードの構造をオブジェクト指向的に定義できます。これにより、文字列を直接操作する複雑さから解放され、より直感的で読みやすいジェネレーターコードを書くことが可能になります。このライブラリの特に便利な機能の一つは、自動的な「using」ステートメントの管理です。生成するコード内で特定の型を使用すると、その型が属する名前空間が自動的に追加されるため、開発者が手動で「using」ステートメントを管理する手間が省けます。また、生成されたコードには、自動生成されたことを示す「GeneratedCode」属性が自動的に付与されます。

まとめとして、C#のソースコードジェネレーターの作成は、最初こそ学習コストが高く、Roslyn APIの理解や、IDEとコンパイラ間の連携における細かい問題に対処する必要があるかもしれません。しかし、一度その仕組みを習得し、「Fluent API」のような強力なツールを使いこなせるようになれば、非常に効率的で、メンテナンスしやすい、高品質なコードを自動生成できるようになります。これは、開発プロセスを大きく改善し、より高度な自動化を実現するための非常に価値のある技術と言えるでしょう。

関連コンテンツ

関連IT用語

関連ITニュース