それでもクロス ターゲット

21 12月

Write once, run anywhereだって?まずはそのふざけた幻想をぶち殺す!

 

まあ、全部は無理です、全部は。ただ、だからこそ、どこでも使えるコードと、どこでもは使えないコードは分けて考えましょう。

昨日は、UI層(ビュー)からロジックを分離しましょうという話をしましたが、ビューがrun anywhereしにくい部分だからというのもあります。

ロジック部分の分離

前に、こんな絵を描きました。

この絵の趣旨は、

  • 処理の中核的なロジック部分は、GUI部分とは分離して作りましょう。
  • 文字ベースでも使えるように作るのがコツです。

という話でした。

こうして分離した純粋なロジック部分は、かなりクロス ターゲットに作れるはずです。

いっそ、プロジェクトを分けて作ってしまうのがおすすめです。

これくらい徹底しないと、ほっとくとすぐにビューやコントローラーにロジックを書いちゃう人が出てきます。何度言ってもすぐに。

 

ちなみに、C#以外への移植が必要な場面(あるいはその逆、他言語からC#への移植)もあるかと思います。その場合でも、中核ロジックだけきっちり分離してある方が、移植は楽でしょうねぇ。

“ターゲット”

“クロス”の話をする前に、クロスにしたい”ターゲット”についてさらっと。いくつかの視点があります。

  • プラットフォーム
    • OSやデバイス、何を使うか
  • マウス/タッチ操作か、スクリプトか
    • わざわざ覚えなくても使いやすいのはGUI
    • 操作を記録しておいたり、一括処理したりしやすいのはCUI
  • サーバーかクライアントか
    • どちら側で処理するか

当たり前ですが、ターゲットが変われば書かなきゃいけないコードも変わります。しかし、そのターゲットごとに書かなきゃいけないコードと、どれでも共通して使えるコードはしっかり分けて作りましょう。

例え、当初予定として、単一のターゲットしか予定になかったとしてもです。

  • 予定は変わるものです
  • 普段から癖をつけておくことで、必要になった時にあわてないようにしましょう
  • これが意識できれば、自然とテストしやすいコードにもなります

 

ロジックの分離の効用

いくつか、効用が得られる状況を見ていきましょう。

UIは陳腐化が激しい

まあ、デバイス自体も変わりますから。この数年、ここまで急激にスマホが伸びると思っていなかった人も多いんじゃないでしょうか。気が付いたらコロッと変わっています。

当然、既存アプリをスマホに対応させてくれなんて要望も多いんじゃないでしょうかねぇ。予想できない勢いで、そういう要望がどんどん出てきます。

そして、UI層まで含めたクロス プラットフォーム開発が現実的でないとなると、ロジックをきっちり分離しておかないと痛い目を見ます。

ユーザーの手動操作ばかりじゃない

システムに、プログラム的にアクセスしたい場合も多いです。

  • CUI提供
  • サービス化

CUI提供

まず、CUIに関してですが、CUIの回で説明した通り、サーバー アプリなどでは、GUIとCUIを両方提供することが望まれます。今、おすすめなのは、PowerShellのCmdlet化してしまうことです。

サービス化

サービス化というのは、システム全体を1枚板に作るんじゃなくて、部品ごとに切り分けて作ってプログラム的に呼べるようにしておくことです。それぞれの部品を「サービス」と呼びます。代表的なのは、ウェブ越しのサービスを呼べるようにしておく「ウェブ サービス化」でしょう。今だと、いわゆるREST APIにしておくのが無難だと思います。

前述の通り、UIは陳腐化が激しく、割と頻繁に作り直しや追加の要件がでます。そして、その時に、元と同じ開発者を使えるとは限らないのです。部品の切り出しをしておかないと、引き継ぎのコストも跳ね上がります。

あるいは、システム開発会社に依頼するほどでもない、ほんのちょっとしたツールが欲しくなることもあるでしょう。サービスAPIがちゃんと公開されていたら、案外内製も簡単だったりします。

ほぼ自動

CUI提供にしろサービス化にしろ、中核ロジックをきっちりライブラリ化してあれば、作るのは非常に簡単です。コマンドや、ウェブ サービスAPIのURLと、プログラム コードの間でかなり単純なマッピングをするだけです。

というか、このマッピング作業は完全自動化できるレベルです。

単体テスト

ロジックの分離は、テストのしやすさにも影響します。前節の通り、プログラム的に扱いやすいようになっているはずなので、テストの自動化もしやすいです。

そして、ロジックを分けましょうの回で説明した通り、テストをしないと死にます。あとから確実に泣きをみます。

サーバーとクライアント

このご時世、処理はサーバー上で行って、クライアントは表示だけにすることも多いです。

ところが、常にネットにつながっているわけじゃない。特に、最近はスマホが流行りですし、通信状況がコロコロ変わります。また、些細なことでいちいちサーバー上に問い合わせていたら、応答性が悪くてストレスフルになったり、帯域圧迫したりという問題もあるでしょう。

そこで、特にゲームなんかだと多いんですが、サーバーと同じ処理をクライアント上でも行うことがあります。ここで1つ注意点としては、処理をクライアント側に移すんじゃなくて、両方で2重に処理する必要があります。クライアント上で計算した結果はあくまでキャッシュ的な扱いで、本当にサーバー側と不整合がないか、どこかで同期をとる必要があります。あるいは、ゲームだと深刻な問題になりますが、クライアントだけで処理してしまうと、いわゆるチート プレイがし放題です。

こういうとき、どちらでも使える状態でライブラリ化してあれば、何の苦労もありません。単一コードを、2つのプロジェクトから参照するだけです。

まあ、現実は…HTMLアプリとかでクライアントがJavaScriptになってしまうと、その夢はもろくも崩れ去るわけですが…。とはいえ、前述の通り、移植をするにしても、ロジックを分離してる方が楽です。

 

少し余談。ひどいものだと、仕様書もくそもなくて、「Flashが仕様みたいなものだから、Flash開発担当の人に聞いて同じものを実装して」みたいな話も…ざらに。

まとめ

いろんなターゲットがあります。

  • UI技術の入れ替わり
  • GUIかCUIか
  • サーバー処理かクライアント処理か

UIまで含めたクロス ターゲットは非現実でも、中核となる処理はだいたいどのターゲットでも動くはず、とういか、動くように作れるべき。

テストもしやすくなりますし、もし別の言語に移植する必要があるときも、ずいぶん楽になると思います。

どのターゲットに対しても使える処理は、独立したライブラリとして作ることをお勧めします。

 

補足

今回も何点か補足。

Portable Class Library

.NET Frameworkといっても、参照可能なクラス ライブラリの範囲が変わる、プロファイル(profile)というものを何種類か持っています。

どのプロファイルからでも使えるライブラリを作るためには、Portable Class Libraryという特別なプロジェクトを作る必要があります。

今回説明したような、「中核ロジックを独立させたライブラリ」を作るなら、このPotable Class Libraryを使うのがいいでしょう。

C#→JavaScript

Googleは結構、JavaからJavaScriptコードを生成してるんでしたっけ?まあ、ですよねー。

.NET界隈でも、C#からJavaScriptコードを生成するようなツールが結構あります。有名なものでは、Script#など。

サービスのメタデータ交換

サービス化するということは、ある誰かがサービスを作って、別のある誰かがそのサービスを参照することになります。そして、通常、両者がソースコードを共有することはないので、「ソース コード → サービスAPI化」のマッピングとは逆に、「サービスAPI → ソース コード」のマッピングもほしかったりします。

そのために、「このサービスはこんなAPI、こんなデータを公開しています」というような情報(メタデータ)も公開したいです。ちゃんとこのメタデータが公開されていれば、サービスの利用側が非常に楽になります。

ロジックを分けましょう

20 12月

本日はちょっとしたホラー話です。警告しても警告してもなくならないエンドレスな物語。

エターナル フォース ブリザード!

効果: プロジェクトは死ぬ

ビューとモデルの分離

みなさん、ちゃんとビューは薄く作っていますか?ビューやコントローラーにロジックを詰め込んじゃっていませんか?

まして、.aspx/.cshtml/.php/.jsp なんかのHTMLテンプレート部分にロジックを書いちゃっていませんか?

まあ、「ビューとモデルの分離」と言われてわかる人は、そりゃ分離しますわね。問題は、言われても何のことかわからない人。というか、わかってない人がプロジェクトに含まれている場合。

HTMLテンプレート中のロジック

ASP.NET MVCのRazorエンジン、便利ですね。軽くもう、C#スクリプトですよこれ。C#書き放題!

とかやってて後から泣くわけですね。例えば、以下のようなコードを書いて。

@using System.Linq;
@{
    ViewBag.Title = "
ホーム ページ";
}

<p>
@{
    Sample[] items = ViewBag.Items;
    var i = items.First();
    if (i != null)
    { 
        <span>@i.Name</span>
    }
}
</p>

「Itemsの先頭要素が、あれば表示したい」というつもりのコードです。つもり。LINQに慣れた人なら気づくと思うんですが、Itemsが0要素の時、このコードは例外を起こして止まります。よく見るあれ、

アプリケーションでサーバー エラーが発生しました。

あれが起きます。

問題はこの行ですね。

    var i = items.First(); // Firstは、要素がないとき例外発生

正しくは、FirstOrDefaultって書かないとダメです。

さらに悪いことに

「こんなのすぐに気づくよ」と思うかもしれません。しかし…これの悲劇は…

以下のような状況を想像してください。

  • このコードは自分で書いたものではありません
    • バージョン管理をしていて、updateをしたときに、他人の書いたコートが混ざったものです
  • ローカル実行では問題が出ませんでした
    • たまたま、自分の使っていたテスト データは要素0なデータが含まれていませんでした
  • ところが本番でだけエラーが出ました
    • 再現条件がわからず、小一時間悩むことに
    • そしてしばらくしてから気づく「あれ、私こんなコード書いたっけ?」

とかいうのが起こりうる現実。

問題と対策

Firstメソッドの仕様がどうとか以前の問題で、テストの自動化の習慣がないことが最大の問題ですね。あと、レビューをきっちり回すプロセスの欠如。

そして、テストの習慣がついてたら、cshtml中にロジックを書くのなんてもってのほか。

GUIのテストは難しい

一般に、GUIはテストがしにくいです。Coded UIテスト(プログラムでで「ボタンを押した」とかのイベントを起こして、ユーザー操作を疑似的に再現してUIのテストをする手法)なんかもなくはないですが。多くの場合、手作業確認になります。

前述の、「0要素の場合の確認が漏れ、本番環境でエラー」なんかも、手作業確認だから漏れるわけです。

あくまでテンプレート

cshtmlなどのファイルは、あくまでHTMLを生成するためのテンプレートです。

デスクトップ アプリに関してはこのAdvent Calendarでもちょこっとだけ話しましたが、以下のような、データ バインディングという仕組みを使って、UIからデータを分離します。

UI側の記述では、「ここにXを表示したい」というような印だけを入れておきます。

cshtmlでも、やるべきことは同じで、この手の印にあたるコードだけを書くべきです。

となると、書けることは限られてきます。cshtml中に残るC#コードは以下の程度なはずです。

  • 一覧表示のためのforeachステートメント
  • プロパティ参照(@item.Xなど)
  • ごくごく簡単な分岐(例えば、0の時だけフォントや文字を変えたいとか)

そしてテストを

分離したデータの側は、単体テストを掛けれるはずです。掛けなきゃいけません。

今回話したようなちょっとしたコードですら、後から悩まされるわけです。テストなしで自信を持って書き換えられますか?

性能問題が出ているコードで、「たぶんここ直せば改善しそう。コード直すのは30分ほどなんですけども。テストがないからちょっと触れないですねぇ。」というもよく聞く話。納期が近づいてからでは遅いんです。最初から、テストを書く習慣を身に着けておかないと。

「スピードが大事なんでテストをしっかりやる時間がないんです」とか言って手を抜いて、あとから苦しむことになって、結局余計に時間がかかるなんてのもよく聞く話。よく聞く話で、よく警告話も耳にするのに、なぜか繰り返される悲劇。

まとめ

  • テストがないと後で死ぬ
  • ビューにロジック書くとテストできなくて死ぬ

Visual Studioを使ったテストの話も、残りのAdvent Calendarのどこかでしましょうか。

WindowsとCUI

19 12月

今日はCUIの話をします。

GUIじゃなくてCUI。グイじゃなくてキュイ。グラフィカルじゃなくて、キャラクター。マウスやタッチ操作じゃなくて、全部文字!

なんか鳴き声みたいですけどキュイ。ウェブで「キュイ」で画像検索したらたぶん吹き出しそうな結果が出てきますけど、キュイ。

アップデートしてますか?

みんな、自分の専門外のことについては驚くほど古い知識のまま更新されずにいます。10年前の話を平気でしてきます。きっと、10光年離れた場所から観測しています。

なので、「Windowsはコマンド プロンプトが使いにくいから…」なんてぼやく人がいても、その人を責めることはできないでしょう。

今はPowerShellがあるのに!

PowerShell

正規表現の回とかでもさらっと出しましたが、改めてご紹介いたしましょう。ザNEWコマンド ライン!! PowerShell。

2006年に登場し、Windows 7やWindows Server 2008には標準搭載されています。

以下のような感じで使います(配色は私の好みで白背景に変えています)。

完全に文字だけのコマンド ラインに加えて、コード補完や色付け表示もしてくれるPowerShell ISE(Integrated Scripting Environment)も付属しています。

次期バージョンではISEのUIを一新するようですねぇ。今、CTP2(コミュニティ向け技術プレビュー版の第2版)ですが、以下のような感じになっています。コード補完回りが大幅強化されるようです。

 

GUI vs CUI

昨日に引き続き、「どっちがいいか?」という質問です。答えは「両方」! GUIとCUI、それぞれいいところがあります。

やっぱり、初見のとっつきやすさでいうとグラフィカルな方がわかりやすいです。それに、可視化ってのも大事です。サーバーの状態などを一目瞭然に把握できるような、素敵UIはあった方がいいです。

一方で、繰り返し同じ処理をするような場合は、スクリプト言語を使った操作をしたいです。それに、GUIを付けるというのは、OSのサイズを大きくしますし、セキュリティ アップデートの頻度も増えます。GUIがなくて済むなら、なしで済ませたいです。前述の可視化なんかも、例えばサーバー クラスターだったりすると、クラスター管理している1台だけが持っていれば事足りたりしますし。

ということで、今のWindowsは、GUIにもCUIにも、両方に本気です。GUIに本気なのは当たり前として、CUIもおろそかにしていません。

コマンド ラインにもGUIを欠かさない

もうすでに紹介していますが、PowerShellには、コードの補完や色付けをしてくれる便利なGUI、PowerShell ISEがあります。

手元のGUIありのクライアントOSでスクリプトを書いて、リモートのGUIなしサーバーOSで実行しましょう。

というか、PowerShellはリモート操作機能も備えていたり(手元のPowerShellコンソールでコマンドをたたいて、リモート上でジョブを動かす)。

PowerShell、急拡大中

PowerShellも登場から5年くらい経ち、だいぶこなれてきましたね。基礎がこなれたところで、応用が急速に進んでいます。

Windows Server 8

Window Serverの次期バージョン、今はコードネームでWindows Server 8なんて呼ばれていますが、Windows Server 8の方針としては、サーバー上で動くアプリは「GUIなしが必須」だそうです。

GUIの提供とともに、PowerShellのコマンド(Cmdlet(コマンドレット)といいます)の提供が必須です。

Windows Server 8自身の管理も、Cmdletでできるよう、大量のCmdletが追加されています。

Cmdlet拡充中

Windows Server 8に限らず、マイクロソフトのサーバー製品関連はCmdlet提供が当たり前になってきています。次のバージョンで、軒並みCmdlet化されそうです。

  • SQL Server 2012
    • すでに、2012年中のリリースが確定したようで、SQL Server 2012という名称でリリース候補版が出ています
    • SQL Server Management Studio中に「PowerShellを起動」メニューがあったり
    • ls Tables とかのコマンドでテーブル操作できたり
  • Windows Azure
  • Team Foundation Server

コマンドが主軸 + オブジェクト指向も

今までも、スクリプトでのOS管理というと、VBS、JSあったわけですが。PowerShellはあくまでコマンド ベースなのと、.NET統合が特徴的です。

コマンド ベース

非開発者向け・IT管理者向けだと、コマンド形式の方が良いみたいですね。なので、主軸がコマンドにあります。

PowerShell専用のCmdletと呼ばれるコマンドだけでなく、今まで通りの、単なるコンソール アプリも呼び出せます。

.NET統合

一方で、ちょっと込み入った処理をしたいときには、C#的なオブジェクト指向なプログラムを書くこともできます。ライブラリ的には、.NET Frameworkのクラスをそのまま使えます。

モード切り替え

PowerShellは、2系統の文法(に加えて、文字列中も特殊な処理が入るので、実質3系統)が混ざってて、状況に応じて切り替わっていたりします。

  • コマンド モード
    • 文字列から始めると、コマンドと解釈されます
    • 以降、引用符なしで文字列を受け付けます
    • 付きの文字はオプション
  • 式モード
    • $から始めると式モードと解釈されます
    • 以降、PerlっぽいようなC#っぽいようなOOP言語になります
      • if, switch, while, do-while, for, foreachなども使えます
      • . でメソッド呼び出し、引数には()必要、文字列には引用符必要

 

(= の直後には、モードの再選択が行われます(= の直後を文字列から始めると、コマンドと解釈されます)。

オブジェクト パイプライン

コマンド モードであっても、.NETオブジェクトが中心的な役割りを担います。Cmdlet(PowerShell専用のコマンド)は、.NETオブジェクトを入出力に使います。

一般的なコマンド ラインと同じく、| (パイプ演算子)を使って複数のコマンドをつなげますが、つないだコマンドが両方Cmdletの場合、データが.NETオブジェクトのまま渡ります。

例えば、以下の例を見てください。

lsコマンド(Get-ChildItemというコマンドのエイリアスです。Unixコマンドっぽいエイリアスが結構な数用意されています)の結果は、DictionaryInfo型の配列になっています。次のselectコマンドで、その.NET型の配列をそのまま受け取って、最初の1項目だけ返します。その結果に対して、.NETのobject.GetType()メソッドを呼んでいるので、結果は、DictionaryInfoを表すType型インスタンスになります。

IsPublic IsSerial Name BaseType
——– ——– —- ——–
True True DirectoryInfo System.IO.FileSystemInfo

 

オブジェクト パイプラインでデータ処理

オブジェクト パイプラインは、ある意味、C#のLINQ的な機構です。

冒頭の、PowerShellの画面キャプチャ中に移っているのがまさにその例だったりします。再掲すると以下の通り。

cat
$file |
foreach { [regex]::Split($_, ‘\s+’) } |
where { $_ } |
group |
sort
Count -Descending |
select
Count, Name -First 10 |
foreach { ‘{1, -12}: {0}’
-f
$_.Count, $_.Name }

foreachwhereなどは、Cmdletとして提供されている1種のデータ処理コマンドです。ちなみに、前段からの入力は、$_ という暗黙的な変数に格納されます。

これで、$file(ファイルのパスを表す文字列)の内容を読んで、単語を集計して、頻度が高いもの10個を、書式指定して表示します。

C#で書くと以下のような感じに。

var q =
    from line in File.ReadLines(file)
    from word in Regex.Split(line, @”\s+”)
    where !string.IsNullOrEmpty(word)
    group word by word into g
    orderby g.Count() descending
    select new { Count = g.Count(), Name = g.Key };

foreach (var x in q.Take(10))
{
    Console.WriteLine(“{1, -12}: {0}”, x.Count, x.Name);
}

ネイティブと.NETと

18 12月

DynamicのついでにILの話したついでに、ネイティブと.NETの対比の話もしましょうか。

 

ここでいうネイティブは、実CPUのネイティブ コード(を直接出力するC++などの言語)のことです。

ネイティブか.NETか、それが問題だ

嘘です。

「AかB、どっちがいい?」って質問の答えは、往々にして「両方」です。残念ながら。毎回毎回、「これ1つですべてを解決!」みたいな銀の弾丸を期待しては、毎回毎回、夢物語に終わるのです。

アプリは.NET(C#とか)で書いた方が楽。それは間違いないです。一方で、インフラ的なところ、データベースやらGUIフレームワークみたいなのの内部はネイティブで書いた方が楽。場合によってはネイティブで書かざるを得ません。極度のパフォーマンスが必要な場面では、.NETで書く方が却って大変になることが多いです。

結局、適材適所としか言いようがないです。じゃあ、それぞれどこが適所なんでしょう?それぞれの利点/欠点をまとめてみましょう。

3つの視点

.NET Frameworkが持っている性質を3つに分けて考えてみます。

  • 共通型システム
  • メモリ管理の自動化
  • CPU独立な中間言語

 

ネイティブとマネージ(managed: .NET Frameworkに管理されているという意味)の対立構造で描かれることが多くて、マネージ コードが持つこの3つの性質はまとめて説明されることが多いですが、互いに独立(にもできる)概念です。

共通型システムを持つことはネイティブな言語でも重要だと思いますし、メモリ管理が手動な中間言語があってもいいと思います。

共通型システム

.NETのライブラリは、C#からでもVBからでも、なんなら、PowerShellやIronPythonなどからでも共通利用可能です。これが可能なのは、共通型システム(common type system)という、型の取り扱いに関する規格を持っているからです。

一番大事

個人的には、.NETの性質のなかで一番大事なものだと思います。

今はもう、ライブラリやフレームワークなくしてアプリなんて作れません。.NETやJavaを見ての通り、標準ライブラリの時点で膨大な量のライブラリがあり、さらに、第3者提供のライブラリも山ほど見つかります。

これだけ大量のライブラリがあって、使いこなすことが要求されると、プログラミング言語自体を覚えることよりも、ライブラリを覚えるコストの方がはるかに大きいです。逆にいうと、ライブラリさえ共通利用できるなら、言語の違いなんて微々たるものです。

Windows 8

Windows 8で、共通型システムの適用範囲が広がります。.NETのメタデータ規格を流用して、ネイティブやJavaScriptでも型を共通利用できるようになります。

Windows 8では、今までのWPFのようなものが、ネイティブ コードで書きなおされました。しかし、新しい共通型システムのおかげで、.NETから見ると、今までと何の変りもなくWPFとまったく同じ感覚で使えます。

利点/欠点 まとめ

共通型システムの利点

  • ライブラリの学習が楽になります
  • 実行に関係ないメタデータを持つことで:
    • 動的コード生成できる
    • セキュリティに関する情報も持てる

共通型システムの欠点

  • メタデータの分、プログラム サイズが大きくなる
  • 標準規格に縛られる
    • .NETとかJava仮想マシンの型システムはOOP前提なわけですが、他のパラダイムを使いたいときにネックにならないか?
    • Java仮想マシンはジェネリックや値型を持っていないのが結構なネックに
    • 「nullを許さない参照型」が欲しかったりするけども、今から追加するにはコストが大きすぎる

メモリ管理自動化

あなたのやりたいことはメモリ管理ですか?

メモリ管理自体が目的になることはないわけですが、その割に、メモリ管理は非常に大変です。

今となっては、むしろ、メモリの自動管理機構を持っていない言語の方が珍しくなってしまいましたねぇ。

マネージ ヒープ

.NETのように、ガベージ コレクション(garbage collection)機能によって管理されたメモリをマネージ ヒープ(managed heap)と言います。

マネージ ヒープは以下のような性質があります。

  • マネージ ヒープは、全体としてのスループット的には非常に性能がいいです
    • ヒープ(動的なメモリ確保)が必要なら、素直にマネージ ヒープに任せる方がいいです
    • ただ、処理負荷がある1点に集中してしまうことがあります
  • 手動管理ではそもそもヒープを使わないような最適化が可能ですが、自動管理の場合はそういう最適化がしにくいです
    • 下手なことをすると、ガベージ コレクションの仕事を阻害して、かえって遅くなります
  • マネージ ヒープは、確保できる物理メモリ量が多めにある時に良い性能を発揮します
    • 省メモリ環境は苦手です
    • 物理メモリを目いっぱい使うようなキャッシュ処理は苦手です

 

管理外リソース

さて、プログラムで使うリソースは、何もメモリばかりではありません。ファイルやグラフィック、ネットワーク接続なんかもあります。これらのリソース管理は、結局自前で行う必要があります。

最悪、メモリの自動解放のタイミングで一緒にこの手のリソースを解放してもいいんですが、無駄に多くのリソースを使ってしまうので、場合によってはかなり性能を落とします。

管理されててもメモリ リーク

ガベージ コレクションは、「誰からも参照されていないゴミを見つけて解放する」というような仕組みで動いています。なので、「本当はもう不要になったのに、誰かがずっと参照しっぱなし」みたいなことをすると、結局、不要なメモリが残り続けます。

イベント駆動なプログラム(GUIアプリなんかだとイベント駆動がほぼ必須)では、参照関係が複雑になりがちで、誰が誰を参照しているかがわからなくなりがちです。参照を外し忘れてメモリ リークしてしまうことも多いです。

利点/欠点 まとめ

メモリ自動管理の利点

  • やりたいことに集中できる
  • セキュリティ ホールを作りにくい
  • ヒープの性能(スループット)が良い
  • メモリ以外のリソースの管理は結局自前

メモリ自動管理の欠点

  • 自前管理との相性があまり良くない
    • 部分的に自前管理で性能上げようとかすると逆効果になりがち
    • そもそもヒープ利用を避ける最適化もしづらい
  • ガベージ コレクション発生時に一時的に応答悪くなることがある

中間言語

昨日、中間言語(IL: intermediate language)の説明をしました。要は、いったんCPU非依存な形式で配布しておいて、実行時に実CPUのネイティブ コードに変換します。

クロスCPU

.NETは、結構いろいろな環境で動くことを想定しています。デスクトップ向けのWindows以外にも、Windows Phone 7はARMですし、Xbox 360のCPUはPowerPCベースです。SilverlightにはMac版もあります。今は、monoもあるので、Linuxなどでも動きます。

同じOSであっても異なるCPUに対応しないといけません。いわゆる32ビット版(x86)と64ビット版(x64)がありますし、Windows 8ではARMプロセッサーにも対応します。

アプリを作る側からしても、それぞれのCPU向けにコンパイルして配布するのは結構面倒です。

コンパイラーを作る側の視点だと中間言語の重要性はもっと増します。プログラミング言語(C#とかVB)の専門家と、CPU毎の最適化の専門家に分かれて作業ができます。プログラミング言語の専門家は中間言語を作るところまで、CPU最適化の専門家は中間言語から先だけ気にすればよくなります。

セキュリティ

中間言語は、命令がかなり高級で、セキュリティ的な検証がしやすいです。.NETの場合は、署名を入れて検証したり、メタデータに必要な権限の情報も入れておけるので、かなり強固なセキュリティ保証ができます。

性能の良し悪し

平均的な状況では、.NETのコードでもネイティブの8~9割の性能が出るといわれています。ただ、ほんとに状況次第です。ネイティブの方が数倍早くなるような状況もありますし、.NETの方が早くなることもあります。

標準C++の範囲のコードならともかく、インライン アセンブラーを使ったCPU依存の最適化を駆け出すと、明らかにネイティブの方が早くなります。そこまでコストをかけてでも性能が必要な場合、.NETは使えません。

また、最近だと、大規模データ処理を、GPUを使って行うような手法(GPGPU: General-purpose computing on GPU)なんかもありますが、これも過度に環境依存するので、.NETからは直接活用しにくいです。

利点/欠点 まとめ

中間言語の利点

  • 配布が容易
    • 1バイナリでいろんなCPU向けに配布可能
  • 命令長が短く、プログラム サイズが小さくなる
  • セキュリティ保証しやすい

中間言語の欠点

  • 多少、性能が犠牲に
    • JITが挟まる
    • CPUに過度に依存する(SIMD系命令とかGPGPUとか)最適化が無理

.NETの中間言語

17 12月

Dynamicの話をしたついでですし、今日は.NETの中間言語(intermediate language: 以下、「IL」と表記)についてお話しましょう。

 

まあ、ほとんどの.NET開発者にとっては無縁な情報ですねぇ。別に見なくてもいいけど、中身もちょっと気になるって人向けの話になります。

それでもやるったらやる!それが私、C#たんっ!

 

まあ、概要程度に。C#プログラマーの人が面白がって読める程度の内容だと思います。

ILを見る機会

IL、昔は多少見る機会があったんですけども。もう、あんまり機会もないですねぇ。

IL逆アセンブラー

.NET Frameworkには、IL逆アセンブラー(ildasm.exe)が標準で付属しています。

もし、ソース コードが手に入らないライブラリの内部挙動を知る必要が出てきた場合、こいつを使えばある程度調べが付きます。

ただ、今だと、C#逆コンパイラーとかも普通にフリーで手に入ります。私の場合は、IL Spyっていうツールを使っています。ILを読むのは結構大変なわけですが、C#化されればだいぶ読めると思います。なので、わざわざIL逆アセンブラーを使う理由はあまりなくなりました。

動的コード生成

「Dynamicの話をしたついで」と言ったのは、昔(.NET 2.0まで)は、動的コード生成にILの知識が必須だったからです。

昨日、DynamicMethodってやつを紹介しましたが、これを使って動的にメソッドを作るには、ILを書かないといけませんでした。

今(3.0以降)では、式ツリーを使った動的コード生成ができるので、ILの知識は不要です。

.NET仮想マシンの仕組み

一応、ILというか、.NETの仮想マシンの仕組みを簡単に説明しておきます。

C#をはじめとする、.NET対応言語は、.NETの仮想マシンが直接解釈できるILマシン語にコンパイルされます。アプリやライブラリは、このILの状態で配布します。

一般的な(仮想マシンか実CPUか問わず)実行環境と同様に、ILには、マシン語と1対1に対応していて、ある程度人間でも読めるような言語(アセンブリ言語)が定義されています。

ILは、.NET Frameworkの仮想マシンによって、都度、ネイティブ コード(実CPUが直接解釈できるマシン語)にコンパイルしながら(Just-In-Time方式のコンパイル、略してJIT)実行されます。

.NETアセンブリの中身

C#などのソース コードのコンパイル結果、つまり、.NET向けの実行可能形式(exe)やライブラリ(dll)を総称して、.NETアセンブリ(assembly)と言います。

アセンブリの中には、以下のように、メタデータ(型情報や属性)と、ILコードが入っています。

メタデータ

昨日お話したような、実行時の型情報利用は、このメタデータの部分から読みだしています。

スタック型マシン

.NETの仮想マシンは、スタック型と呼ばれるタイプの構造をしています。スタック型マシンでは、演算や関数の引数や戻り値を、すべてスタック上に積んでいきます。

例えば、以下のようなC#コードを書いたとしましょう。

var x = int.Parse(Console.ReadLine());
var y = int.Parse(Console.ReadLine());
Console.WriteLine(“{0} + {1} = {2}”, x, y, x + y);

以下のようなILが生成されます。

.method private hidebysig static void Main() cil managed
{
.entrypoint
.maxstack 5
.locals init (int32 V_0,
int32 V_1)
IL_0000: nop
IL_0001: call string [mscorlib]System.Console::ReadLine()
IL_0006: call int32 [mscorlib]System.Int32::Parse(string)
IL_000b: stloc.0
IL_000c: call string [mscorlib]System.Console::ReadLine()
IL_0011: call int32 [mscorlib]System.Int32::Parse(string)
IL_0016: stloc.1
IL_0017: ldstr “{0} + {1} = {2}”
IL_001c: ldloc.0
IL_001d: box [mscorlib]System.Int32
IL_0022: ldloc.1
IL_0023: box [mscorlib]System.Int32
IL_0028: ldloc.0
IL_0029: ldloc.1
IL_002a: add
IL_002b: box [mscorlib]System.Int32
IL_0030: call void [mscorlib]System.Console::WriteLine(string,
object,
object,
object)
IL_0035: nop
IL_0036: ret
} // end of method Program::Main

 

このILを、幾分か端折って、実行していく様子を見ていきましょう。

最後は、3をボックス化した後、4引数のConsole.WriteLineを呼んで、スタック上の値をすべて消費して、結果をコンソールに表示します。

スタック型とレジスター型

.NETのILに限らないんですが、多くの仮想マシンはスタック型マシンになっています。

一方で、実CPUはだいたいレジスター型と呼ばれる構造をしています。スタックとは別に、レジスターと呼ばれる、高速に読み書き可能な記憶領域(個数が限られています)を持ちます。

コンパイラーがスタック型の命令を作るのは結構簡単です。仮想マシンの命令がスタック型になっていることが多いのはこのためです。レジスター型のCPU向けのコンパイラーであっても、一度スタック型の中間言語を生成した後で、実際のレジスター型の命令に置き換えるようなものも多いです。

命令長

.NETのILの命令は、マシン語にしたとき、ほとんどが1バイト命令です(使用頻度の低いいくつかの2バイト命令、4バイト命令もあります)。また、一般的に、スタック型マシンのコードは、レジスター型マシン(たいていの実CPUはレジスター型)よりも短くなります。

後述するように、かなり高級な命令セットを持っているのもあって、ILコードはかなりコンパクトになります。実CPUのネイティブ コードと比べると、下手すると10倍くらいは小さくなります。

(もっとも、その分、メタデータがでかいので、全体としては10倍とは行きませんが。)

アセンブリ言語だけど、かなり高級言語

一般的にいうと、マシン語(アセンブリ言語)は、実行環境でできることそのままな、低級言語です(ここでいう高低は、ハードウェアに近いか(低)、遠いか(高)を表します)。しかし、ILの場合は、そもそも.NETの仮想マシンがかなり高級です。なので、ILも、下手するとC言語のようなネイティブ言語よりもよっぽど高級です。

例えば、以下のような仕組みを持っています。

  • (前述の例を見ての通り)スタックに任意の型を格納できる
  • オブジェクト指向命令
    • フィールドの読み書きや、メソッドの呼び出しが1命令でできます
    • 仮想メソッドの呼び出しも1命令です
  • 例外処理の機構を持っています
  • ジェネリックにILレベルで対応しています
    • 共変性・反変性のフラグも持っています

 

(ちなみに、ジェネリック対応以外は、Java仮想マシンもだいたい同じような仕組みを持っています。)

C#との対比

あとの細かい点は、C#と対比しながら話しましょうか。

  • intなどのいくつかの型は、加減乗除など、専用の命令を持っています(プリミティブ型と呼ばれます)
    • ちなみに、decimalはプリミティブではないです。ただの構造体
  • デリゲート、列挙型は特別扱いを受けています
    • 内部的にクラスになったりするわけではなく、別定義
    • 一方、null許容型はただの構造体です
  • 配列も結構特殊な扱いを受けています
  • 文字列(stringクラス)は単なるクラスですが、リテラルの扱いが多少特殊です
    • C#で、文字列だけは参照型なのにconstを付けれるのはそのため
  • ポインター型もあります
  • 加減乗除などの命令には、オーバーフローのチェックをするタイプとしないタイプとがあります
    • チェックするタイプでは、オーバーフロー時に例外を発生させます
  • switchステートメント相当の専用命令があります
    • 状況に応じて、if-else的なコードにJITするか、ジャンプ テーブル的なコードにJITするか選んでくれるそうです

 

C#にはあるけど、ILには直接はないもの:

  • インデクサー
    • 内部的にはプロパティ扱いです
  • ユーザー定義の演算子
    • 単なる静的メソッドになります
  • ループ(while, for, foreach)
    • ifとgoto的なコードに展開されます
  • ラムダ式、イテレーター、非同期メソッド、dynamic
    • かなり込み入ったコード生成してます
    • イテレーターとかラムダ式に至っては、クラスが生成されたりしてます
  • クエリ式
    • 割かし単純なメソッド呼び出しへの置き換え
  • lockステートメント
    • Monitorクラスに丸投げ
  • 拡張メソッド、デフォルト引数、dynamicな引数
    • 属性が付くだけ

 

ILにはあるけど、C#にはないもの:

  • 本当の意味での可変長引数
    • C#のものは、配列の自動生成で実装しています
    • ILレベルでは、任意個数のスタックを消費してメソッドを呼び出す方法があります
  • 変数の間接参照
    • C#だと、引数を参照渡しするときしか間接参照がおきませんが、ILレベルではもっといろいろ使える参照ロード/ストア命令があります
  • デリゲートとは別に、関数ポインターを持っています

動的処理

16 12月

今日のテーマは動的(dynamic)です。

最初に注意しておきたいのは、動的と言っても何を動的に行うか、いろんなやり方があって、いろんな用途があります。動的ローディング、動的コード生成、動的型付けなどなど、「動的~」の「~」の部分をちゃんと考えましょう。

動的ローディング

既知の型を、未知のDLLから読み込みます。

例えば以下のような感じ。System.Reflection.AssemblyクラスのLoadメソッドなどを使ってDLLを読み込んで、System.Activator.Createメソッドでインスタンスを作ります。

インスタンスを作る部分だけ面倒ですが、一度インスタンスを作ってしまえば、あとは普通に(特に苦労することなく)使えます。

用途1: プラグイン

プラグイン、つまり、アプリ本体とは別の第3者がアプリへの拡張機能を提供する場合、まさに、既知の型を未知のDLLから読み込むことになります。

用途2: ホット デプロイ

アプリ本体を稼働させたままで、部分的に機能を置き換えたい場合があります。その場合、置き換えたい部分をプラグインとして作っておいて、更新が必要なときに再読み込み(あるいは、DLLファイルの監視をしておいて、新しくなったら再読み込み)する仕組みを作ります。

便利ライブラリ: MEF

こういうプラグイン的な動的ローディングをサポートするためのフレームワークとして、MEF(Managed Extensibility Framework)というものがあります。

MEFは、.NET Framework 4からは標準ライブラリに取り込まれました。System.ComponentModel.Composition名前空間以下のクラスがMEFの実体です。

リフレクション(型情報使った処理)

型がどういうメンバー(メソッドやプロパティなど)を持つかというような、型情報を使った処理を書きたいことがあります。

この手の情報は、実行時には必ずしも必要のない情報で、プログラミング言語によっては実行時に残さない(コンパイル時にだけ使う)こともあります。そういう意味で、メタデータ(metadata: データに関するデータという意味。この場合、プログラムというデータを作るためのデータ)と呼ばれたりもします。

.NETでは、GetTypeメソッドなどを使って型情報を実行時に取得できます。型情報は、Type型のインスタンスとして表されます。

型情報を実行時に取得することをリフレクション(reflection: 反射。ここでは自己反映的という意味合い)と呼びます。

用途: シリアライズ

型情報を使った処理の代表格は、データのシリアライズ(serialize: 直列化する)です。独自のバイナリ形式であったり文字列化であったり、一定のルールでデータを保存・復元することをシリアライズ(復元の方はデシリアライズ)と呼びます。

コンピューターをまたいだ通信でデータを受け渡ししたり、ファイルなどに保存するために使います。

もちろん、型ごとに独自のシリアライズ処理を書いても構わないんですが、だいたいは定型的な処理になるので、個別に書くのは面倒です。そこで、型情報を使って動的にシリアライズしたりします。

具体例: XML化、JSON化

データ形式が何でもいいなら、自分で処理を書く必要はなく、標準ライブラリ機能を使えばいいでしょう。以下のようなクラスが標準提供されています。

その他、オープン ソースなライブラリで、Json.NETDynamicJsonなども有名です。

動的コード生成

静的な処理(コンパイル済みのコードの実行)と比べると、リフレクションはそれなりに重たい処理です。もともとコンパイル時に全部済ましてしまうような処理をその都度掛ける分重たいわけです。だいたい、2・3桁くらい遅いです。2倍じゃなく、2桁差。

そこで、動的にコードを生成して、その生成したコンパイル済みのコードを取っておいて、使いまわそうという発想が出てきます。この方法なら、重たい処理は最初の1回だけでよくて、2回目以降は十分高速になります。

.NETでは、動的コード生成の手段として以下のようなものがあります。

  • 式ツリー
    • System.Linq.Expressions名前空間以下のクラスを使います
    • 名前通り、ツリー構造のデータを使ってプログラムを表現します
    • ラムダ式からの生成もできます。
    • .NET 3.0で式相当のコード、.NET 4で一通りなんでもコード生成できるようになりました
  • System.Reflection.Emit.DynamicMethodクラス
    • IL(.NETの中間言語、アセンブリ言語)を直接記述します
    • 式ツリーが入る以前の、旧時代の遺物ではあります
  • CodeDOM
    • System.CodeDom名前空間以下のクラスを使います
    • 文字列でC#などのソース コードを作って、それをコンパイルします
    • 内部的に、C#などのコンパイラーを直接呼び出しているだけです
      • 現状、あまり使い勝手の良い仕様にはなっていません
      • 正直、Roslyn待ち

用途1: リフレクションの高速化

本節冒頭の通り、一番の用途はリフレクションの高速化です。

たいていのシリアライズ用のライブラリでは、内部的には動的コード生成しています。

用途2: スクリプティング

アプリ中で、ちょっとしたスクリプト言語を使いたい場合があります。アプリ中でのスクリプト実行は、当然、動的コード生成になります。

昨日説明した通り、IronPythonなどが利用できます。

ゆるい型付け

通常、C#のような、静的で厳密な型を持つ言語では、あるオブジェクトに途中でプロパティやメソッドを足すということはできません。

しかし、C# 4.0でdynamicキーワードが導入されて、ゆるい型(実行時にいろいろ追加可能)が使えるようになりました。

dynamic d = new ExpandoObject();
d.X = 10; // 
この瞬間、 X というメンバーが追加される
d.Y = 20; // 
同上、追加
Console.WriteLine(d.X + d.Y);

ここで使ったExpandoObjectを含め、System.Dynamic名前空間以下のクラスを使います。

用途1: DLL間の依存関係をなくす

通常、クラスなどの型を使いたければ、その型を定義しているDLLをコンパイル時に参照する必要があります。そのDLLに依存しないとコンパイルできません。

しかし、まれにですが、無理やりにでもDLLの依存関係を切りたいことがあります。結構無理やりな手段ですが、そういう場合にdynamicキーワードが使えなくもないです。

用途2: スクリプト言語連携

IronPythonなどの基盤であるDLR(dynamic language runtime)は、内部的にSystem.Dynamic名前空間のクラスを使います。dynamicキーワードを使って、簡単に連携可能です。

というよりも、.NET 4の動的機能、System.Dynamic名前空間内のクラスは、DLRの成果を.NETに取り込んだものです。

用途3: ゆるい型のデータ連携

JSONを使ったRESTサービスなどでは、いわゆるスキーマレス(schema-less: データ構造をきっちり決めてない)になっていることがあります。

dynamicキーワードを使えば、この手のスキーマレスなデータとの連携がお手軽になります。

動的に型の挙動を変える

ある型の特定のメソッドの挙動を動的に差し替えたり、インターフェイスを継承した型を動的に生成したりしたいことがあります。

この場合、動的に型を作ることになります。型の動的生成には、以下のようなクラスが使えます。

  • System.Reflection.Emit.TypeBuilder
    • 型情報(Type型)を動的に作ります
    • メソッドなどの挙動も動的にコード生成できます
    • 作った型情報を元に、Activator.Createします
  • System.Runtime.Remoting.Proxies.RealProxy
    • インターフェイスのメソッド呼び出しをフックして、別の処理をはさむ機能を提供します

用途1: 透過プロキシ

例えば、以下のようなクラスを考えてみます。

public class IService
{
    void SendMessage(string message);
}

public class Service : IService
{
    public void SendMessage(string message)
    {
        // 
具体的な処理
    }
}

普通にインスタンスを作って普通に使うと、以下のようになります。

これに対して、インターフェイスとクラスの間に別の処理をはさみたいことがあります。わかりやすい例は、通信をはさんで、サーバー上で処理を行いたい場合です。

こういう、間に挟むもののことをプロキシ(proxy)と呼びます。特に、この例のように、利用側からするとプロキシが挟まっていることを意識しないで使えるもののことを透過プロキシ(transparent proxy)と呼びます。

プロキシ用途の場合、ビルド時コード生成という手段もあるんですが、動的に(実行時に)型生成することも多いです。

用途2: モック

あるメソッドをテストしたいときに、そのメソッドが別のメソッドに依存している場合、どうすればいいでしょう。

依存先のメソッドが完成するまで待つと、どんどん開発が遅れます。また、最初は正しく動いていたけど、あとから依存先の方にバグが混入したら、こちらのメソッドまでテストが通らなくなったり。

ということで、依存先のメソッドをモック(mock: 模造品)で差し替えたいことがあります。こういう場合、型を継承した別クラスを動的に作って、所望のメソッドだけ置き換えるというような方法を取ります。

便利ライブラリ: Moq

モック生成のためだけにTypeBuilderなどを使うのは結構大変なので、補助してくれるライブラリを使うのが一般的です。モック生成用のライブラリは、結構いろんなものがオープン ソースで提供されています。

有名どころだと、Moq(もきゅ?)とかでしょうか。以下のような使い方ができます。

var mock = new Moq.Mock<IComparer<int>>();
mock.Setup(m => m.Compare(0, 1)).Returns(-1);
mock.Setup(m => m.Compare(1, 0)).Returns(1);
mock.Setup(m => m.Compare(0, 0)).Returns(0);

var c = mock.Object;
Console.WriteLine(c.Compare(1, 0));

Moqは、NuGetでもインストールできます。

型情報の動的生成

メソッドなどの挙動までは必要なく、「この型はこういうプロパティを持っている」というような、メタデータだけ動的に作って提供したいことがあります。以下のようなクラスを使います。

  • System.ComponentModel.ICustomTypeDescriptor
    • .NET 4/Silverlight 4以前で使います
    • Type型とは別系統で、TypeDescriptorなどのクラスを返す仕組みでした。Type型を返すことでも同じことができるので、後述のICustomTypeProviderで置き換わる予定です
  • System.Reflection.ICustomTypeProvider
    • .NET 4.5/Silverlight 5以降で使います
    • Type型で型情報を返します

用途: データ バインディング

WPFやSilverlightでは、UIの方(いわゆるビュー。XAMLで書くやつ)には、「ここにXの値を表示したい」というような印だけ入れておいて、実際のデータは外部から渡します。

この際、渡したデータの型情報に基づいて、文字列から数値への変換や、変換に失敗した際のエラー処理などを自動的にやってくれています。こういう仕組みをデータ バインディング(data binding)と呼びます。

そこで問題になるのは、渡すデータがゆるい型の場合。データ バインディングは内部的にいろいろ動的な処理をしているわけですが、渡す側も動的だと、型情報が取れなくて困ります。

そこで、ゆるい型に対して、別途、ちゃんとした型情報をでっちあげるために使うのが、ICustomTypeProviderなどのインターフェイスです。このインターフェイスを実装している場合、実際の型情報(GetTypeした結果)よりも優先して、別途用意した型情報に基づいたデータ バインディングを行ってくれます。

補足

今日、延々と説明してきた動的処理の類は、.NETの中でも一番不安定というか、変化が激しい部分ですねぇ。進化の真っただ中にあるのが原因ではありますが、ちょっと目を離したすきになんか変わっちゃってます。

DynamicMethodが過去の遺物(式ツリーを使いましょう)になってたり、ICustomTypeDescriptorICustomTypeProviderに変わったり。

Windows 8, Metroアプリ向け.NET

実は、Windows 8では、.NET Frameworkが2系統に分かれます。

  • デスクトップ向け
    • 今まで通りです
  • Metro(スレートPC向けのタッチUI)向け
    • デスクトップ向けとは別系統ライブラリが入った.NET Frameworkになります

この、Metro向け.NETでは、Type型をはじめとした、リフレクション回りの仕様が大きく変わります。

  • 古いスタイルのAPIを削除
    • DynamicMethodなどは使えなくなっています
  • 現状のType型を、Type型とTypeInfo型の2つに分離
    • System名前空間とSystem.Reflection名前空間の間の依存を切るためだそうです
    • 元々、.NETのメタデータ上は2つに分かれています
      • TypeRef: 型の識別にだけ使う情報 → Type
      • TypeDef: リフレクション用の詳細な情報 → TypeInfo
  • System.Reflection.Emit廃止
  • System.Runtime.Remoting廃止

 

基本的には「重複削除」なので問題ないんですが、今日紹介した中でいうと、型の挙動を変える類の処理(透過プロキシやモック)ができなくなっています。

もちろん、今はまだプレビュー版なので、製品版までに変更があると思います。

スクリプティング

15 12月

RoslynがNuGet配布されましたね。

 

ということで、本日は予定を変更して、スクリプト エンジンとNuGetの話をしましょうか。

元の予定が何だったのかは秘密♪

 

今日のサンプル コード: CsharpScriptingSample.cs

NuGet

NuGetは、オープン ソースなライブラリを簡単に使うための仕組みです。

  • NuGet gallery: オープン ソース ライブラリを公開するための公式サービスです。
  • NuGet Package Manager: Visual Studioの拡張で、NuGet galleryで公開されているライブラリをお手軽検索&インストールするためのツールです。

NuGet Package Manager自体のインストールもお手軽で、Visual Studio 2010をお持ちの方は、拡張機能マネージャーを立ち上げて、「nuget」で検索してみてください。

ただし、拡張機能マネージャーは基本的にProfessional以上のグレード(有償)の機能です。しかし抜け道もあって、以下のいずれかを使えば、無償版でも拡張機能マネージャーを(そしてNuGetも)利用できます。

 

.NET用スクリプト エンジン

Roslynの前に少々寄り道しましょうか。.NET用のスクリプト エンジンと言えば、IronPythonに代用される、DLR(dynamic language runtime: 動的言語ランタイム)スクリプト。IronPythonIronRubyIronJSがNuGet経由でインストールできたりします。

ひゃっはー!さっそくインストールだーっ!

プロジェクトの「参照設定」を右クリックして、「Manage NuGet Packages…」を選択します。

すると、NuGet Package Managerが立ち上がりますが、右上に検索ボックスがあるので、「iron」で検索しましょう。

 

ここでは、とりあえず、IronPythonを使ってみましょう。検索結果の中から、IronPythonを選んでダブル クリックすればOKです。

ちなみに、IronRubyとIronPythonで、参照しているDLRのバージョンが違ったりするので、同時にインストールするとビルドに失敗したりします。ご注意を。

IronPythonを使ってみよう

インストールさえしてしまえばあとは簡単。以下のようなコードで、PythonコードをC#プログラム中で実行できます。

var engine = IronPython.Hosting.Python.CreateEngine();
var code = @”
data = (1, 2, 3, 4, 5)
q = (x * x for x in data)
sum(q)
;

var x = engine.Execute<int>(code);
Console.WriteLine(x);

var f = engine.Execute<Func<doubledouble>>(@”
from math import *
lambda x: sin(x * x)
);
Console.WriteLine(f(10));

Pythonのラムダ式からFuncデリゲートへのキャストまでしてくれるみたいです。

Roslyn

さて、本日のメインディッシュ、Roslynです。

Roslynとは

Roslyn(コードネームです。マイクロソフトのプレビュー製品のコードネームはだいたいどこかの地名だったり)は、C#コンパイラーの中身をライブラリ公開するものです。次の次(C# 6.0?今のペースだと、2014年頃正式版?)での導入を目指して開発が進んでいます。以下のものを含んでいます。

  • Visual Studio拡張を作るためのプロジェクト テンプレート
    • C#エディター上で、リアルタイムで警告したり、右クリック メニューでリファクタリング機能を提供したり
  • C#/VBコンパイラー
    • C#/VBコードをコンパイルする際の、中間結果を含めていろいろ中をのぞけます
      • 構文解析結果の式ツリー
      • 意味解析結果の、エラーの一覧や、変数の依存関係
  • C#スクリプティング
    • C#をスクリプト言語として使うためのエンジン
    • DLR準拠(使い勝手がほぼ同じというか、サブセット)

 

NuGet経由でインストールできるのは、下の2つです。Visual Studio拡張は、Roslyn本体をインストールする必要があります(Visual Studio拡張に関しては、Visual Studio自身に手を入れる必要がありますが、残りは単なるライブラリです)。

ちなみに、かなりの早期プレビュー版なので、C#の文法のうち、まだ実装されていないものが結構あります。

Roslynを使ってみよう

あとは、IronPythonの時とほとんど同じです。C#スクリプティングは、Roslyn.Scripting.CSharp名前空間にあります(最終的にはSystem名前空間?それとも、Microsoft名前空間?)。

var engine = new Roslyn.Scripting.CSharp.ScriptEngine(
    references: new[] { “System”“System.Core” });
var code = @”
using System.Linq;
var data = new int[] { 1, 2, 3, 4, 5 };
var q = data.Select(x => x * x);
q.Sum()
;

var x = engine.Execute<int>(code);
Console.WriteLine(x);

var f = engine.Execute<Func<doubledouble>>(@”
using System.Math;
x => Sin(x * x)
);
Console.WriteLine(f(10));

ScriptEngineの作り方が少し違う(直接newするのと、参照するアセンブリを引数で指定する)くらいで、残りは同じです。

ラムダ式に対してちゃんと型推論が働いている(x => Sin(x * x) だけでFunc<double, double> 扱いされてる)のはありがたいですねぇ。

あと、地味に、スクリプト専用の文法が入っていたりします。静的クラス(この例ではMathクラス)をusingすることで、静的メソッド(Sinメソッド)を直接書けるようになります。

まとめ

NuGet galleryに入ったことで、誰でもかなりお手軽に「C#スクリプト」を使えるようになりました。

Roslynの本領はVisual Studio拡張の方にあったりする上に、まだまだプレビュー版なので、実は結構「おもちゃ」感あったりしますが。今から慣れ親しんでおけば、数年後に何かが花開くかも!