Deep Insider の Tutor コーナー
>>  Deep Insider は本サイトからスピンオフした姉妹サイトです。よろしく! 
次世代コンパイラー“Roslyn”概説(前編) 【正式版対応】

次世代コンパイラー“Roslyn”概説(前編) 【正式版対応】

Visual Studio 2015の新機能“Roslyn”とは

2015年8月19日 改訂 (初版:2014/09/19)

Visual Studio 2015に採用された次世代コンパイラー「Roslyn」の概要を解説。これまでの進化過程を振り返り、そのAPIレイヤーや、Roslynにより強化されたC#/VB言語機能の一部について紹介する。Visual Studio “14” CTP3→正式版に合わせて改訂。

Microsoft MVP for .NET / Microsoft Student Partners 五十嵐 祐貴
  • このエントリーをはてなブックマークに追加

本連載について

 本連載では、Visual Studio 2015に搭載された、新しい.NETコンパイラープラットフォーム(.NET Compiler Platform。コード名および通称は“Roslyn”。「ロズリン」と読む、以下、Roslynと表記)に関して、その概要とRoslynを用いたプログラミング手法を、前後編に分けて簡単に紹介する。

Roslynとは

 普段、IDE(統合開発環境)を利用してコーディングする際、その背後ではどのようなプロセスが働いているか、考えてみよう。

 Visual Studioであれば、単純なキーワードマッチを超えたセマンティックなシンタックスハイライト、IntelliSense(=セマンティックなコード補完)、リアルタイムなエラー分析、多様なリファクタリングツールなど、多くの機能が動作している。これらの機能は、IDEが独自に構文解析と意味解析を行った結果を、各種ツールへ提供することによって実現されているのである。

 さて、IDEを使って書き終えたコードがコンパイラーに渡されると、コンパイラーはIDEとは独立して構文解析・意味解析を行い、結果を出力する。特にコンパイラーは実際にアセンブリ(.NETではMSILコード)を出力しなければならないため、複雑なコード分析や最適化を行っているが、そのために解析を行って得た中間情報の大部分は、コンパイラー・プログラムの終了と同時に破棄されてしまう。

 これらのことから、求められている“成果物”は違うとしても、IDE側とコンパイラー側の双方で同様な処理を行う部分が発生する。開発チームは、この双方の保守が必要となる上、特に新機能を追加する場合は、IDE側とコンパイラー側の仕様を合わせる必要があり、その調整には非常に労力がかかる。

 これらの問題を解消するため、IDE側にとって必要な「リアルタイム処理性」や「ソースコードが途中で変更された場合への柔軟な対応」などの要件を満たし、中間情報をAPI経由で取得可能な、新しいコンパイラーの開発が必要とされた。それがRoslynである。

 Roslynはマイクロソフトが恩恵を受けるためだけのものではない。Roslynによって提供されるAPIは、SDKをインストールすることで簡単に操作でき、一般の開発者も、比較的容易にVisual Studio向けのリファクタリングツールやコード解析・修正ツールを作成可能である。例として、社内向けのコーディング規約を意識したツールや、Code-Awareなライブラリ(「作成者の意図したライブラリの使い方を基に、ライブラリ利用者の書いたコードを検証する」ツールを同封したライブラリ)の作成などが考えられる。作成したツールは拡張機能として広く配布することが可能であり、Visual Studioユーザーは公開されている拡張機能を、自由にインストール可能である。

Roslynのこれまで

 Roslynは2011年に初のCTP(コミュニティ技術プレビュー版)が発表され、図2.1に示すように、CTP2で匿名型やイベントのサポートなど多数の既存の言語仕様サポート、CTP3で式ツリーのサポート、Previewではasyncawaitのサポート、そしてVisual Studio 2015のリリースに合わせてCTP5、CTP6、RC、RTMと進化を遂げてきた。

図2.1 Roslynのこれまで

Roslynが提供するAPIレイヤー

 Roslynでは、IDE側が必要とする情報を、各種APIを用いることで取得可能である。これについて、2015年8月現在、Roslynのドキュメント(英語)では以下のように説明されている。

図2.2  Roslynが提供するAPIレイヤー

2015年8月現在、ドキュメントに掲載されている図である(「Roslyn Overview ・ dotnet/roslyn Wiki」より引用)。

 下から順に、箇条書きで説明しよう。

  • Compiler APIs: 構文木やフロー分析など、主にコード解析・コンパイラーに関するAPIを提供する。
  • Workspace APIs: プロジェクトファイルの構成や、参照関係などのプロジェクトファイル全体を把握する必要があるAPIを提供する。
  • Feature APIs: 各種リファクタリングやCode Fix(後編で解説)などに用いるAPIを提供する。
  • Scripting APIs: Preview版までは、Compilerレイヤーの一部としてC#/Visual BasicのREPL(対話型評価環境: 対話的にスクリプティングできる環境)やScripting APIが含まれており、実際に利用できた。しかし、公式サイトのOverviewおよびFAQによると、REPLとScripting APIは現在設計の見直しを行っているようである。

 Roslynに関するその他の内容に関しては、「.NET Compiler Platform (“Roslyn”) Overview(英語)」を参照してほしい。

Roslynによる新機能を体験する

 それでは実際に、Roslynによる新機能の一部を体験してみよう。

Roslynが動作する環境の準備

 最新のRoslynによる機能を体験するには、最新のVisual Studio 2015が必要である。最新のVisual Studioのインストーラーは、Visual Studioのダウンロードページからダウンロードできる。

 2015年8月現在、Visual Studio 2015がインストール済みである仮想マシンのイメージをAzureで利用することも可能である(図3.1)。AzureでのVisual Studioの利用方法に関しては、「Visual Studio付きWindowsインスタンスの利用方法」を参照してほしい。

図3.1 Azureのイメージギャラリー

2015年8月現在、仮想マシン作成時のギャラリーから、Visual Studio 2015がインストール済みのイメージを選択可能である。

Roslynにより強化されたC#/VB言語機能

 Visual Studio 2015に搭載されているC#およびVisual Basicコンパイラーは、Roslynにより大幅な改良・新機能の追加がなされている。また、リファクタリング機能もRoslynベースのものへと刷新され、特に今回、Visual Basic向けには初めてリファクタリング機能が追加された(図3.1)*1

図3.2 Visual Basicにおけるリファクタリング機能

Visual Studio 2015ではVisual BasicでもC#と同様にしてリファクタリング機能を利用できる。

  • *1 Visual Basicでは[名前の変更]機能だけは利用可能であったが、「メソッドの抽出」機能などを含む、リファクタリング機能として公式から提供されるのは初めてである。

 誌面の都合上、今回はC#に追加された一部の新機能のみを取り上げることにする。

 Visual Studio 2015を起動し、[新しいプロジェクト]ダイアログで[Visual C#]の[Console Application]テンプレートから新規プロジェクトを作成しよう。

 Visual Studio 2015では標準でC# 6.0の機能が有効となっているため、そのままC# 6.0のコードを記述しても、エラーなく編集・コンパイル可能である。参考までに、null伝搬と式形式の関数メンバー、文字列補完を使ったサンプルを提示する。なお、C# 6.0で導入された新しい言語機能に関しては、「C# 6.0で知っておくべき12の新機能」を参照してほしい。

C#
using System;

class Circle
{
    public int Radius { get; } = 0;            // ……1
    public Circle Child { get; } = null;       // ……2
    public double GetArea() => (Radius * Radius * Math.PI);  // ……3
    public double GetAreaWithoutChildArea() =>
      GetArea() - Child?.GetArea() ?? 0;       // ……4

    public Circle(int radius, Circle child = null)
    {
        this.Radius = radius;
        this.Child = child;
    }

    public override string ToString()
    {
        return $"{DateTime.Now :HH時mm分ss秒} - Area: {GetArea()} , HasChild: {(this.Child == null ? "No" : "Yes")}";    // ……5
    }
}

class Program
{
    static void Main(string[] args)
    {
        var foo = new Circle(5, new Circle(3));
        Console.WriteLine(foo.GetArea());
        Console.WriteLine(foo.Child?.Child?.GetArea() ?? 0); // ……6
        Console.WriteLine(foo.GetAreaWithoutChildArea());
        Console.WriteLine(foo.ToString());
        /* 実行結果
        78.5398163397448
        0
        50.2654824574367
        02時13分31秒 - Area: 78.5398163397448 , HasChild: Yes
        */
    }
}
リスト3.2 C# 6.0で追加された構文を用いたコード
  • 12: 自動実装プロパティ用の初期化子を用いて、初期値を記述する。
  • 3: 処理内容を式形式で表現した関数を宣言する。Childプロパティの有無を考慮しないで、外円の面積を求める。
  • 43と同様に式形式で表現した関数を宣言する。null伝搬演算子(?.)を用いて、Childプロパティの値がnullでない場合は、外円の面積から内円の面積を除いた面積を求める。内円が設定されていない場合は、GetArea()と同様の挙動を示す。
  • 5: クラスに関する詳細を示した文字列を、文字列補完を用いて作成し、返している。
  • 64と同様、null伝播演算子を用いた例。この場合、内円の内円は設定されておらず、nullを返すため、「0」が出力される。

 なお今後のC#およびVisual Basicに取り入れる言語機能については、定期的に議論が行われており、GitHubのissueとして公開されている。詳しくは「Language Design Notes(英語)」を参照してほしい。

まとめ

 今回はRoslynの概要と新機能の一部を説明した。次回はRoslyn SDKのインストールを行い、実際にRoslynを用いたプログラミングを行ってみる。

次世代コンパイラー“Roslyn”概説(前編) 【正式版対応】
1. 【現在、表示中】≫ Visual Studio 2015の新機能“Roslyn”とは

Visual Studio 2015に採用された次世代コンパイラー「Roslyn」の概要を解説。これまでの進化過程を振り返り、そのAPIレイヤーや、Roslynにより強化されたC#/VB言語機能の一部について紹介する。Visual Studio “14” CTP3→正式版に合わせて改訂。

次世代コンパイラー“Roslyn”概説(前編) 【正式版対応】
2. 新しいコンパイラー“Roslyn”を用いたプログラミングを体験!

.NET Compiler Platform SDKをインストールしたVisual Studio 2015開発環境を使って、Roslynを用いたプログラミング方法を実際のコードで示しながら説明する。Visual Studio “14” CTP3→正式版に合わせて改訂。

サイトからのお知らせ

Twitterでつぶやこう!