DLR メモ書き

DLRに関するメモ書き残しとく。

ちなみに、DLR 0.9(Dec 11 2008 のバイナリ)の話。

下準備

  1. codeplex のサイトからリリースバイナリを取ってくる
  2. zip展開する
  3. 参照
    1. C#のプロジェクトから以下の三つのDLLを参照する
    2. 残りのDLLは実行ファイルと同じフォルダにコピー
      • 自分はプロジェクトに含めてしまって、プロパティの「出力ディレクトリにコピー」の項目を「新しい場合はコピー」にした
    3. App.Config をコピーしてプロジェクトに追加

C# からスクリプトコード呼び出し

  • 基本的な流れは
    1. ScriptRuntime runtime = ScriptRuntime.CreateFromConfiguration();
    2. ScriptEngine engine = runtime.GetEngine("拡張子");
    3. CompiledCode code = engine.CreateScriptSourceFromFile(path).Compile();
    4. code.Execute();
  • C#スクリプトに値渡して、計算結果を C# 側で受け取るのがいまいちやりにくい
    • 1.0 になったら少しはましになるのかなぁ
static void ExcuteSum()
{
    var x = new[] { 1, 2, 3, 4, 5 };
    var q = x.Select(p => p * p);

    ExcuteSum(Path.Combine(basePath, "sum.py"), q);
    ExcuteSum(Path.Combine(basePath, "sum.rb"), q);
}

static readonly ScriptRuntime runtime = ScriptRuntime.CreateFromConfiguration();

static CompiledCode GetCompiledCode(string path)
{
    var ext = System.IO.Path.GetExtension(path).Replace(".", "");
    var engine = runtime.GetEngine(ext);
    return engine.CreateScriptSourceFromFile(path).Compile();
}

static void ExcuteSum(string path, IEnumerable<int> list)
{
    var compiled = GetCompiledCode(path);
    var scope = runtime.CreateScope();

    scope.SetVariable("arg", list);
    // ↑ 引数を渡す機能とかないみたい?なので、変数として値をセット。

    object result = compiled.Execute(scope);
    // ↑ IronPython だとこれで戻り値を返せない。

    if (result == null)
    {
        result = scope.GetVariable("result");
        // ↑ 逆に、IronRuby だと、result 変数が scope に残らない。
    }

    Console.Write("{0}, {1}\n", result, result.GetType().Name);
    // ↑ 55, Int32 って表示されるはず
}

sum.py の中身。

sum = 0

for x in arg :
	sum += x

result = sum

# sum            # IronPython では、これで戻り値返せない
# sys.exit(sum)  # これで値を返せるけども、エラーコードになる。非0だと異常終了扱いされる

sum.rb の中身。

sum = 0

arg.each do |x|
	sum += x
end

# result = sum # IronRuby だと、スクリプト実行後、result 変数がスコープに残らない

sum # 戻り値

ユーザー定義型の受け渡し

  • C# で書いた型を IronPython, IronRuby に渡すのは何の問題もない
  • IronPython で書いた型を IronRuby に渡してもプロパティアクセスできない。逆もまたしかり
    • ドキュメント読んでる感じ、正式版までにはできるようになりそうな雰囲気だけど

例:

まず、以下の Python コードを実行。

x = 3

class Point:
	def getValue(self):
		return self.__v

	def setValue(self, val):
		self.__v = val

y = Point()
y.Value = 5

z = y.Value * y.Value

次に、以下の Ruby コード。

print x * x
print z
# ↑この2行はちゃんと実行できる

p y
# ↑表示結果は #<IronPython::Runtime::Types::OldInstance:0x000005c>

#print y.Value
# ↑この行、「undefined method `Value'」って怒られる

class Point
  attr_accessor :x, :y

  def initialize(x, y)
    @x = x; @y = y
  end
end

$w = Point.new(3, 4)

v = $w.x * $w.y
$v = $w.x * $w.y

$w

IronRubyスクリプトを実行しても、変数がスコープに残らないので、次、Python に値を渡すために C# 側で以下のような作業をする。

var result = c2.Execute(scope); // 前述の Ruby コードの実行
scope.SetVariable("w", result);
c3.Execute(scope);              // 後述する Python コードの実行

で、最後に以下の Python コードを実行。

#print v
# ↑この行、「'v' is not defined」って怒られる

print w.GetType().Name
# ↑表示結果は IronRuby.Builtins.RubyObject

result = w.GetType()

#result = w.x * x.y
# ↑この行、「'RubyObject' object has no attribute 'x'」って怒られる