graphics.hatenablog.com

技術系テクニカルアーティストのあれこれ

Roslyn の CSharp.Scripting を使ってみる。

自分用のメモも兼ねてざっくりまとめてみる。
github.com



基本的なことは ここ をみればだいたいいける。Eval とかの API はだいたい Async になってて、逐次処理がしたければ返ってくる Task を Wait() するなり ContinueWith() するなり。

いわゆるインタプリタ実行になるから基本的にはそのまま CSharpScript クラスから EvaluateAsync() とか RunAsync() すればいいし、キャッシュも効いてるから 2 回目以降はちゃんと速い。
明示的にコンパイルしたいときは Compile() で、これは Async じゃないから並列化したければ Task.Factory.StartNew() とかで。eval が async になってることからわかるように、別スレッドでコンパイルした結果を使うのも特に問題なし。

eval/run/compile したときの結果は CSharpScript.GetCompilation() からアクセスできる。構文解析の結果は Compilation.SyntaxTrees に入ってて、それを GetRoot() すれば SyntaxNode にアクセスできる。そこから構文木を辿っていけばいい。

コンパイル結果のアセンブリも Compilation の中に抱えられてて、Assembly が欲しいときは一旦ストリームに展開してから Load してあげる。こんなかんじ↓

using (var stream = new MemoryStream())
{
    if (script.GetCompilation().Emit(stream).Success)
    {
        var assembly = Assembly.Load(stream.GetBuffer());
        ...
    }
}

ただ、スクリプト側とホスト側とでデータのやりとかも普通にできるから、例えばスクリプト内で定義された Type が欲しいだけのときなんかは、場合によっては ScriptState.ReturnValue や ScriptState.Variables 経由で Type 型のインスタンスを受け渡してしまうのも手軽でいいかもしれない。

だいたいそんなかんじ。これに SyntaxNode の自前ツリー構築なんかを組み合わせればたいていのことはやりたい放題にできると思う。