RubyでGUI C#からRubyを呼び出す
IronRubyの1.0がリリースされたので、C#からRubyの呼び出しを試してみる。
まず、C#のプロジェクトを作成。
formにtextboxとbuttonを一つずつ配置する。
デザイナのbuttonをダブルクリックしてForm1の編集画面へ。
編集前に、参照設定にIronRuby/bin下の
IronRuby.dll
IronRuby.Libraries.dll
Microsoft.Dynamic.dll
Microsoft.Scripting.dll
を追加しておく。
以下、ソース
using System; using System.Collections.Generic; using System.ComponentModel; using System.Data; using System.Drawing; using System.Linq; using System.Text; using System.Windows.Forms; using IronRuby.Hosting; // ここ以下が追加分 using IronRuby.Runtime; using IronRuby.Builtins; using Microsoft.Scripting.Hosting; namespace CallRubySample { public partial class Form1 : Form { public Form1() { InitializeComponent(); } private void button1_Click(object sender, EventArgs e) { var rt = IronRuby.Ruby.CreateRuntime(); // IronRubyのランタイム作成 dynamic test = rt.UseFile(@"..\..\test.rb"); // スクリプト読み込み dynamic ret = test.foo(this.textBox1.Text); // フクリプトのfooメソッド呼び出し this.textBox1.Text = ret; // 結果をtextboxに表示 } } }
呼ばれる側のtest.rbの内容。
ソースフォルダに配置するが、VSのエディタで編集するとBOM付きで保存されてしまって実行時にエラーになるので、外部のエディタで編集すること。
def foo(s) s + "Foo" end
Buttonクリックで、textboxに入っていた文字列の後ろに"Foo"が追加される。
C#側の処理のポイントは"dynamic"で定義されている変数。コンパイル時にはRubyスクリプトに"foo"というメソッドが定義されているかは不明なのでdynamic型で定義しておいて、実行時に"foo"が定義されていなかったらエラーになる。
ここで、Rubyスクリプトのfooの定義を以下のように変更してみる。
def foo(s) "Foo" + s end
こうすると
this.textBox1.Text = ret;
の行で"IronRuby.Builtin.MutableStringをstringに暗黙の変換ができません"という例外が発生する。
s + "Foo"
では、C#のStringクラスのインスタンスがレシーバになっているので、C#のString型で返されるが、
"Foo" + s
では、RubyのStringがレシーバになっているのでRubyのString型が返される。
この場合は
this.textBox1.Text = (string)ret;
のようにキャストする必要がある。
Rubyの方でも型変換する必要があるケース。
def foo(s) eval(s).to_s end
これは、sがRubyのString型でないのでevalでエラーになる。
eval(s.to_s).to_s
としてあげる必要がある。