rider.お品書きサクッと書いて公開して、後でちまちま修正する事がママあります。なんじゃこりゃ?と思ったら、数日してから見て貰えると嬉しいです。「スクラムの実践方法を分かりやすくマンガも交えて解説。2015リリースが近づいてきました。今回はC#的にはあまり大がかりな拡張がありませんが、内情としてはC#コンパイラのインフラが「Roslyn」に正式対応するという事で、地味に大きな変更となっています。Roslynは、MSのオープンソース戦略としては早い段階で公開され、それ以来、パブリックな場で将来のC#コンパイラの仕様検討などが行われています。ソースコードも「オープンソース」として公開されており、自分でいじりたければフォークも可能です。概要を掴んでおこうと考えている方向けに、いくつかリンクを張っておきます。Basic次世代コンパイラ「Roslyn」をオープンソースで公開。独自言語など開発可能に。Frameworkに付属していました。このプログラムはアンマネージコード(多分、C++)で書かれており、メンテナンスが大変そうだなと思います。Studioが、ソースコードエディタ内でインテリセンスを表示させるために、csc.exeとは「別に」、独自にソースコードのパースを行っており、言語仕様の変化に合わせて二重にメンテナンスしなければならないという問題もありました。Resharperなどのサードパーティプラグインも、この内部実装にはアクセスできないため、またもや同じようなパーサーを独自に書かなければならず、どう考えても不健全です。いうのがRoslynです。(InfoQ)なワードだけが取りざたされて、何か大きなサービス的なもののように誤解されたこともありましたが、要するにコンパイラのための(低レベルな)インフラをライブラリ化して、様々な環境から共通利用出来るようにしたものです。C#と言ってますが、VB.netもRoslyn化されています。この記事では「スクリプティング」に焦点を置きたいと思います。C#で書かれているので、既に同じようなインフラが存在する事になります。Monoのインフラを使ったスクリプティングインフラとして、「scriptcs」が存在します。このプロジェクトは、スクリプティングのモジュール化に必要な「スクリプトライブラリ」を作る事が出来たり、スクリプトから参照するライブラリをNuGetから取得(実行時に配置、即使用可能)出来たりと、スクリプト環境としての熟成を図っているようです。Roslynがリリースされたことで、scriptcsのインフラを、MonoかRoslynかで選択可能にしようとしています。Coreプロジェクトと相互に情報交換して、.NET純正のソースコードのMonoへの取り込みや、Monoの相互運用性(Linux対応など)の.NETへの取り込みを行う事を表明しています。C#コンパイラのインフラについては、Roslynベースに統一する方針のようです。スクリプトが使えるようになるのです。ゲームの世界ではluaやpython辺りをよく聞きますね。本体をC#で書いているなら、スクリプトもC#で書きたいものです。別の例として、Officeを挙げます。Application」という、VBチックなスクリプト環境があります。VBAは徐々にフェードアウトの方向になっていると思いますが、代わりにC#でスクリプトが書けたら、もうちょっとOfficeに前向きになりそうです(Excel向けであれば、商用プラグインが既にあります:FCell)。分かりませんが、Roslynが公開されたことで、その可能性は高くなったと思います。Roslynのコアは、C#のパーサーライブラリです。library化されています)。パースしても構文木が得られるだけで、これが実行可能になるわけではありません。scripting」です。流れは以下のようになります。scriptingは、構文木をコンパイルしてIL命令に変換し、更に実行まで行います。IL変換は、System.Reflection.Emitを使用して動的にILを生成します。Emitは環境によって使用出来ない(例:ストアアプリ環境であるWinRTではEmitは使えない)ため、Roslyn本体には含めなかったのだと推察しています。scriptingは.NET4.5以上の環境でのみ使用可能です。scriptingを使ってスクリプト環境を作る場合、殆どRoslynを意識する必要はありません。worldをやってみましょう。4.5以上のコンソールアプリケーションのプロジェクトを作ってください。次に、NuGetで以下のパッケージを導入します。正式版ではないので、「リリース前のパッケージを含める」を選択して下さい。RCでGoLiveなので、インターフェイスに大きな変更は無いと思われます。コマンドでインストールすると確実です。scriptingの実装を書きます。思うかもしれませんが、大丈夫です。ところで、ソースコードの先頭にコメントを入れておきましたが、興味深い事に気が付きましたか?Consoleクラスは、本来はSystem名前空間に存在しますが、指定していません。System;」相当の定義が組み込まれているからです。このコード自体、名前空間の宣言も、クラス宣言も、メソッド宣言もありません。スクリプト環境でこれらを書くことももちろん出来ますが、スクリプト環境ではこれらを省略可能にしているのです。そのため、いきなり実装本体が来ても、全く問題ありません。上記のように、スクリプティングの世界では、単にソースコードをリアルタイムで解析・実行するだけではなく、普通のソースコードとは異なる状況に対処する必要があります。以下にそのような課題を挙げます。記述の省略を可能にする逐次処理を可能にするホスト環境と通信する記述の省略を可能にする前述のように、スクリプト環境では色々省略して記述出来た方が便利です。ホストする側で、事前にusingを成立させておくことが出来ます。「System」名前空間は既定で定義されていますが、独自の名前空間も定義しておくことが出来ます。そのためには、事前にScriptOptionsクラスを用意して、オプションとして指定します。list));",options);script1.Run();}}}ScriptOptionsや他のクラスもそうですが、Roslynでは「イミュータブルオブジェクト」を全面的に採用しています。イミュータブルオブジェクトとは、文字列(System.String)や日付構造体(System.DateTime)のように、インスタンスの内容が不変である事を保証した実装の事です。一度生成されたインスタンスは、中身が変更されることはありません。上記の例では「WithNamespaces」メソッドを呼び出していますが、これによって、最初に生成したScriptOptionsクラスのインスタンスを変更するのではなく、新たなScriptOptionsクラスのインスタンスを生成しています。以下がWithNamespacesの定義です。(内部実装)}このように、WithNamespacesを呼び出すと、名前空間をオプションとして追加した「新しいScriptOptions」を生成し、戻り値として返却します。そのため、単にWithNamespacesを呼び出しただけでは、元のインスタンスには何も変更が加わっていない事になるので注意が必要です。ScriptOptions())ので、mscorlibへの参照を追加しておく必要があります。それが「WithReferences」メソッドです。最初の例でオプションを省略しましたが、省略時はmscorlibへの参照と、System名前空間の定義だけが行われた状態になっています。して必要な定義を追加したオプションを生成出来れば、あとは、CSharpScript.Createの引数にオプションを渡すことで、これらの定義が解釈されます。一般的には、「System」「System.Collections.Generic」「System.Linq」「System.Threading.Tasks」などが定義されていた方が、利便性が向上するでしょう。これらの定義をホスト側のApp.configや設定ファイルから読み込むようにすれば、更に柔軟性が高くなります。逐次処理を可能にするスクリプト環境では、ユーザーがコンソールからインタラクティブにコードを記述する可能性があります。コマンドプロンプト(cmd.exe)やPowerShellでは、ユーザーがコマンドラインから入力した命令やコードが「Enter」キーの押下で、即実行されます。言う事は、コンパイル実行の場合は、一度にすべてのコードを評価しなければならないのが、ちょっとづつ、断片的にソースコードが渡される可能性がある事を意味します。この状況を、とりあえず簡単に記述したのが以下の例です。line!\");");script2.Run();}}}単に、CSharpScriptのインスタンスを2回生成して実行しているだけです。これは問題ないでしょう。変数「data」が定義されていますが、スクリプトとしては問題ありません。問題はscript2です。このスクリプトで、data変数を参照しようとしていますが、コンパイルエラーが発生しています。これは、script1とscript2が、相互に全く関係のないスクリプトとして実行しているためです。そのように意図している場合は問題ありませんが、インタラクティブに実行する場合は、このようにコードが分断されてしまう可能性は十分考えられます。script1で定義されたdata変数をscript2で参照可能にするには、「ScriptState」を使います。data);");script2.Run(script1State);}}}CSharpScript.Runメソッドの戻り値は、ScriptStateです。この中には、スクリプトを実行した結果や、スクリプトとして記憶しておくべき様々な情報が格納されています。これを、次のスクリプト実行時のRunメソッドの引数に渡すと、スクリプトはScriptStateの記憶を前提とした環境で動作します。この中にはdata変数の結果も格納されているので、script2も問題無く実行出来るようになるのです。次の問題が片付けば、大抵の環境に組み込んで、すぐに応用が可能ですよ!ホスト環境と通信するここまでで、独立したスクリプトエンジンとして問題なく操作できるようになったはずですが、現実には、スクリプト側のコードから、ホスト環境のオブジェクトを操作したりしたい訳です。なければ、スクリプト環境を組み込む意味がありませんよね。前述のCSharpScript.Runメソッドの引数の定義を見て、疑問に思ったかもしれません。(内部実装)}Runメソッドの引数は「object」です。ここに渡していたのはScriptStateクラスのインスタンスなので、わざわざobjectと定義する意味が分からないかもしれません。実は、この引数にはScriptStateだけではなく、任意のクラスのインスタンスが渡せます。CreateValues(10));");script1.Run(hostObject);}}}ホスト側で用意した「HostObject」クラスのインスタンスを渡し、スクリプト側からアクセスしています。面白い事に、スクリプトからはグローバルな無名の要素としてアクセス出来ます。そのため、「Value」フィールドや「CreateValues」メソッドに、インスタンスやクラスの指定がありません。Runの引数に渡せるインスタンスは、クラスである必要があります(構造体はダメです。クラスのメンバーに構造体があっても問題ありません)。クラスはパブリックでなければなりません。スクリプトがコンパイルされた際に、クラスのメタデータにアクセスする必要があるからでしょう。残る課題ここまで分かれば、後は応用だけです。スクリプト環境として考えられる他の課題は、scriptcsを見てみると分かるかもしれません。インタラクティブな指令で、アセンブリ参照を追加するインタラクティブな指令で、スクリプトをファイルとしてロードするインタラクティブな指令で、NuGetなどのパッケージシステムをサポートするつまり、インタラクティブなコンソールがコードの入力となる場合は、帯域外の指令で、ホストがスクリプティングのサポートをする必要があります。scriptcsでは、このような独自コマンドを定義(先頭が”:”で始まるコマンドが入力された場合は、スクリプトコードではなく独自に処理を行う。”:load”でスクリプトライブラリをロードする)して対処しています。WordPress%d人のブロガーが「いいね」をつけました。