本サイトからスピンオフした姉妹サイトです。2015開発環境を使って、Roslynを用いたプログラミング方法を実際のコードで示しながら説明する。CTP3→正式版に合わせて改訂。2015に搭載された、新しい.NETコンパイラープラットフォーム(コード名“Roslyn”。以下、Roslynと表記)の概要を説明した。2015とRoslynを用いた、プログラミング手法を簡単に紹介する。SDKをインストールする必要がある。2015のインストール時に、全ての機能をインストールした場合はこの手順は、この節の手順は読み飛ばしてよい。2015項目を右クリックし、(表示されるコンテキストメニューから)[変更]をクリックする。Studioのダイアログが表示され、[変更][修復][アンインストール]のいずれかを選択する画面になったら、[変更]ボタンをクリックする。これにより、図4.1の画面が表示される。2015をインストールする場合には、インストール時に[カスタム]を選択することで、以下の説明と同様の画面で進めることができる。インストールする機能の選択画面(図4.1)の中から、以下の項目がチェックされているかを確認し、チェックされていなければチェックを付ける。図中で赤く囲まれた項目にチェックを付ける必要がある。チェックしたら、[次へ]ボタンをクリックして、インストールを完了しよう。SDKをインストールする。Studio向け拡張機能を作成する際に必要となる。拡張機能」にアクセスして[ダウンロード]ボタンをクリックすると(図4.2)、.vsixファイルがダウンロードされる。このファイルを開くと、自動的にVSIXインストーラーが起動するので、画面の指示に従ってインストールを進めよう。SDKのダウンロードリンクページ上部にある[ダウンロード]ボタンからダウンロードが可能である。Visualizerは、このパッケージをインストールすることで同時に導入されるようになっている。しているコードが、Roslynではどのような構文木で構築されているのかをリアルタイムに視覚化できるツールである(図4.3)。Fixなどの作成時に大いに役立つため、ぜひ覚えておいてほしい。Visualizerを動作させた様子エディターで入力されているコードに対応する、Roslyn上での構文木が表示される。ツリーに表示されているアイテムをクリックすることで、該当する部分のコードがコードエディターで選択される。Roslynを使ってみよう。行い、その結果に基づいて簡易的な色付けを行ったコードを出力する、スタンドアロンなコード解析プログラムの作成を行う(図5.1)。GitHub」で公開している。シンタックスハイライトをRoslynによって行い、その結果が表示されている。構文解析と意味解析さっそくコードを見ていこう。今回、Roslynを用いて重要な処理を行っているのは、SampleSyntaxWalker.csファイルのみである。構文解析と意味解析は、それぞれ以下のコードで行っている。構文解析と意味解析を行う処理(SampleSyntaxWalker.cs)CSharpSyntaxTree/CSharpCompilationはMicrosoft.CodeAnalysis.CSharp名前空間、MetadataFileReferenceはMicrosoft.CodeAnalysis名前空間に所属するクラス。HtmlBuilderは、HTMLソースを出力するために独自に実装したクラスである。1コードに対して構文解析を行い、構文木を含む結果を変数treeに格納する。2構文解析を行った結果から、コードに対する診断(構文エラーなど)を取得する。31で得た構文解析結果と、参照(今回はmscorlibアセンブリのみを含めている)情報を基に、コンパイル環境を作成し、意味解析を行う。Model)を取得する。53で解析した結果から、コードに対する診断(構文エラー、意味エラーなど)を取得する。文字列/文字/数値リテラルのシンタックスハイライト続いてシンタックスハイライトの実現方法であるが、これは構文解析で得た構文木の全ノードを走査するだけである。RoslynにはVisitorパターンで実装されたSyntaxWalkerクラス(Microsoft.CodeAnalysis名前空間)が用意されているため、今回はそのクラスを継承して、Visitメソッドをオーバーライドすることで、走査を行った。構文木を走査する処理(SampleSyntaxWalker.cs)SyntaxTokenはMicrosoft.CodeAnalysis名前空間、SyntaxKindはMicrosoft.CodeAnalysis.CSharp名前空間に所属するクラス。TokenKindは、トークン種別管理用に独自に実装した列挙体である。1トークンがキーワードであるかを確認する。234トークンがキーワードでない場合、どのようなものであるかを確認する(ここでは、文字列リテラル、文字リテラル、数値リテラル、......の順で確認している)。識別子のシンタックスハイライトまた解析対象のコードに、foo.Action()のようなコードが含まれていた際に、fooがどのようなものであるかを確認して、そのハイライトを適切に行う必要がある。そこで、意味解析の段階で作成した意味モデルを用いて、その識別子(Identifier)が何を表すかを取得する。識別子に対する処理(SampleSyntaxWalker.cs)SimpleNameSyntaxはMicrosoft.CodeAnalysis.CSharp.Syntax名前空間、SymbolKindはMicrosoft.CodeAnalysis名前空間に所属するクラス。hoge;)の型が、SimpleNameSyntaxと互換性があるかを判定する。2トークンの親(=SyntaxNodeの派生クラス、この場合はSimpleNameSyntaxクラスのオブジェクト)を取得する。3取得した情報を基に、その親の識別子がどのようなものであるか、意味モデルを用いて判別する。4識別子がNamedType(=クラス名や列挙型名など)を指している場合は、色付けを行う。5識別子が名前空間や変数やプロパティである場合は、色付けなしで出力を行う。{})であるかを確認する。識別子がどのような意味を持つか、判断する仕組みを独自で実装した場合、シンボルテーブルや名前解決の仕組みなど非常に複雑な実装を行う必要があったが、それらの情報がRoslynを用いることで、非常に簡潔に取得できることがよく分かる。サンプルプログラムの実行サンプルとして、このプログラムにリスト5.4を入力とした出力結果を、リスト5.5、図5.2に示す。プログラムに入力として与えたサンプルコード(BadCode.cs)このコードを、.csファイルとしてUTF-8エンコードで保存する。1セミコロンが抜けているため、構文エラーが発生すると考えられる。2いんとと呼ばれる名前を持つ型は宣言されていないが、構文に問題はない。output.htmlというコマンドで、サンプルプログラムを実行すると、このような結果がHTMLページとして出力される。12セミコロンが抜けていることが検知されている。3意味解析部分では、いんとと呼ばれる名前を持つ型が存在しないことを示している。出力された色付きのコード構文エラーや未解決の名前があるにもかかわらず、該当箇所以外に関しては影響を受けず、シンタックスハイライトが行われている。2015へと組み込むことのできる拡張機能を、Roslynを用いて作成する。サンプルプログラムのダウンロード今回、公式サイトが用意しているWalkthrough(英語)で用いられているサンプル(MakeConstプログラム)が、非常に分かりやすいため、そちらのコードを利用して解説していく(※こちらのリンク先から閲覧・ダウンロードできる)。GitHub」に用意したので、併せて参照してほしい。今回は、このサンプルプログラムと同じものを、「MakeConstFix」という名前で作成する。サンプルプログラム「MakeConstFix」の内容このプログラムでは、定数化可能な変数を検出すると通知を発行し、ユーザーへ修正の提示を行う(図6.1)。APIsの1つとして紹介した)。10;)を検出すると、通知を発行し、ユーザーへ修正の提示を行う。MakeConstFixが正常に動作するための条件このプログラムが正常な動作を行うには、純粋に変数の宣言文を検出するだけではなく、以下の条件を満たす必要があることに注意したい。10;となる必要がある)。Fixプロジェクトを作成しよう。C#]にある[Extensibility]を選択する(図6.2)。VSIX)]を選択して、プロジェクト名を入力し、[OK]ボタンをクリックしよう。VSIX)]テンプレートを選択する。Studioおよびユーザーに通知する処理が必要となる。リスト6.1では、診断機能がどのような構文を対象とし、どのような処理を行うかを宣言している。診断機能の宣言部分(DiagnosticAnalyzer.cs)プロジェクト作成時にひな型として基本的なコードは生成されている。ここで追記・編集した部分は太字にしている。※実際に自分で生成したひな型コードと、一部、変数名が違う場合もあるので注意してほしい(例えば、変数「MakeConstDiagnosticId」は、ひな型では「DiagnosticId」という名前で出力されている場合がある)。12この診断に関する情報(カテゴリや警告レベル)を宣言する。Studioから受け取る情報を宣言する。リスト6.1のRegisterSyntaxNodeActionメソッド呼び出しの引数で指定したSyntaxNodeがRoslynによって検出されたとき、引数で指定したAnalyzeNodeメソッドが呼び出される。このAnalyzeNodeメソッド内で定数化できるかを判別し、可能である場合には通知を発行する処理を記述する(リスト6.2)。AnalyzeNodeメソッドは、同じDiagnosticAnalyzerクラス内に以下のように記述すればよい。(DiagnosticAnalyzer.cs)ひな型コードではAnalyzeSymbolメソッドが生成されているが、それを消してこのAnalyzeNodeメソッドに書き換える。1CanBeMadeConstメソッド(後述)に、検出されたSyntaxNodeを渡して、定数化可能であるかを判定する。2判定可能と判断された場合には、通知を発行する。続いて、CanBeMadeConstメソッドを以下のように記述する。診断機能の判定部分(DiagnosticAnalyzer.cs)1修飾子にconstがすでに含まれている場合は対象外とする。0;は定数化できない)。foo();は定数化できない)。4宣言された変数に対してデータフロー解析(=その変数の参照状況の解析など)を行う。5宣言された変数が他の箇所で書き換えられていないことを確認し、書き換えられている場合は対象外とする。constキーワードを設定できるのは、値が変更されないことが保証されるものに限られるためである。61~5の条件に全て当てはまる文は定数化できるとして、trueを返す。以上までのコードで、診断機能が動作する。Studioの実験的なインスタンスを起動した後、(コンソールアプリのプログラムを新規に作成するなどして)動作確認してみよう。正常に診断機能が動作している場合、図6.3のような通知が発行されるはずである*1。10;)を検出すると通知を発行する。この例では、定数化されているfoo、宣言後に代入が行われているbazには通知が発行されず、barのみに発行されていることが分かる。Fixで表示される文字(例:図6.4)に文字化けが発生する場合は、先ほどのDiagnosticAnalyzer.csファイルの文字エンコーディングを見直す必要がある。文字エンコーディングは(メニューバーにある)[ファイル]メニューの[保存オプションの詳細設定]から変更可能である。65001」に設定しよう。続いて、ユーザーが通知を確認した箇所に対して発行する、修正機能の作成を行う。修正機能の宣言部分(CodeFixProvider.cs)プロジェクト作成時にひな型として基本的なコードは生成されている。ここで追記・編集した部分は太字にしている。1通知を行った範囲において、LocalDeclarationStatementSyntaxクラス(Microsoft.CodeAnalysis.CSharp.Syntax名前空間)であるトークンを見つける。2修正情報を返す(修正を適用する場合、MakeConstAsync()を実行した結果、返される構文木を採用する)。それでは、木の改変を行うMakeConstAsyncメソッドのコードを見ていこう。修正機能の処理部分(CodeFixProvider.cs)ひな型コードではMakeUppercaseAsyncメソッドが生成されているが、それを消してこのMakeConstAsyncメソッドに書き換える。Microsoft.CodeAnalysis.Simplification;というコードがファイルの冒頭に必要になる。1前方にあるTrivia(=空白など)を削除した宣言文を新しく作成する。2前方にTriviaを付与した、constキーワードを新しく作成する。3もともとあった修飾子リストの先頭に、constキーワードを追加した修飾子リストを新しく作成する。4宣言部分のみを取得する。53で作成した新しい修飾子リストと新しい宣言部分で、1で作成した宣言文を置き換えた、変数の宣言文を新しく作成する。65で作成した宣言文に整形を行った宣言文を新しく作成する。7構文木のルートを取得する。8localDeclaration(=今回の修正対象部分)をformattedLocal(=新しいノード)で置き換えた構文木を、新たに作成する。98で作成した構文木で構成されるドキュメントを新しく作成し、その結果を返す。リスト6.5のコードでは、既存の構文木に対して変更を加えるメソッドの呼び出しや代入を一切行っておらず、どの処理においても、ある部分のみを改変したクローンの構文木を生成している(Immutableな構造となっている)ことに注目したい。これはRoslynによって生成された構文木が、悪意のあるプラグインによって変更されるのを防ぐためである。以上のコードで診断機能と修正機能の作成が完了した。Ctrl+F5キーを押して動作確認を行おう。正常に動作している場合、図6.5のような通知が発行され、修正機能が提示されるはずである。10;)を検出すると、通知を発行し、修正の提案を行う。10;が提案されている。Fixを一から作成することになった場合、この作業は非常に労力がかかるであろう。Visualizer]で表示できる)。Visualizerを活用すると、その解決策が見えてくるかもしれないことを覚えておこう。まとめ前回はRoslynの概要を取り上げ、今回は、サンプルプログラムを用いながら、その機能の一部を使用したプログラミング方法を学んだ。Roslynは現在も開発途中であり、日々多くの人々が議論を行いながら、魅力的な進化を遂げている。Studioにとって重要な基盤の一部となっているのは間違いないであろう。Roslynによって、今後の.NETがより大きく成長していくことに期待したい。2015に採用された次世代コンパイラー「Roslyn」の概要を解説。これまでの進化過程を振り返り、そのAPIレイヤーや、Roslynにより強化されたC#/VB言語機能の一部について紹介する。CTP3→正式版に合わせて改訂。2015開発環境を使って、Roslynを用いたプログラミング方法を実際のコードで示しながら説明する。CTP3→正式版に合わせて改訂。機械学習エンジニアを目指す人~初中級者のための技術情報サイトです。「機械学習&AI」「クラウド&ビッグデータ」「IoTデバイス」のネット記事情報を共有中。開発者のためのSlackチーム、作りました:「機械学習&AI」「クラウド&ビッグデータ」「IoTデバイス」のネット記事情報を共有中。2020最適なビューへの切り替えを推奨します:スマートフォン用表示に。