4

私はIronRubyを使用していて、C#メソッドでブロックを使用する方法を見つけようとしています。

これは私がエミュレートしようとしている基本的なRubyコードです。

def BlockTest ()
  result = yield("hello")
  puts result
end

BlockTest { |x| x + " world" }

C#とIronRubyで同じことをしようとする私の試みは次のとおりです。

 string scriptText = "csharp.BlockTest { |arg| arg + 'world'}\n";
 ScriptEngine scriptEngine = Ruby.CreateEngine();
 ScriptScope scriptScope = scriptEngine.CreateScope();
 scriptScope.SetVariable("csharp", new BlockTestClass());
 scriptEngine.Execute(scriptText, scriptScope);

BlockTestClassは次のとおりです。

public class BlockTestClass
{
    public void BlockTest(Func<string, string> block)
    {
        Console.WriteLine(block("hello "));
    }
}

C#コードを実行すると、次の例外が発生します。

引数の数が間違っています(1の場合は0)

IronRubyスクリプトを次のように変更すると、機能します。

 string scriptText = "csharp.BlockTest lambda { |arg| arg + 'world'}\n";

しかし、元のRubyの例と同等になるように、元のIronRubyスクリプトで動作させるにはどうすればよいですか?

 string scriptText = "csharp.BlockTest { |arg| arg + 'world'}\n";
4

3 に答える 3

2

Rubyのブロックは、c#(または他の.Net言語)が理解できる概念ではありません。

デリゲートのc#の同様の概念に「1つを渡す」には、理解できるもので「ラップする」必要があります。

ブロックからラムダを作成することで、デリゲートまたは式を期待してc#コードに渡すことができるものになります。

これは、「関数ポインター」がデリゲートとして実装されていないf#のような祝福された言語の場合でも、「Alt.Net」コミュニティに共通の問題ですが、代わりに、これらの1つをに渡すためにわずかに異なる方法で実行されます(たとえば、f#のFastFuncインスタンス)。 c#の例のようなものでは、デリゲートでラップする必要があります(文字通り、呼び出しによってパラメーターが基になるインスタンスに渡され、結果が返されるデリゲートが作成されます)。

このような変換は自動で行うとより良いと主張することもできますが、それを行うと複雑で奇妙なエッジケースやバグが発生する可能性があり、多くの開発者はコードを見るだけでこのようなラッピング操作が行われることを知りたがっています。また、常に妥当な変換が行われるとは限らない(または複数存在する)場合もあるため、ユーザーに何が起こるかを決定させるのが賢明なデフォルトです。

于 2010-02-18T12:15:09.070 に答える
1

ほとんどの場合、IronRuby ProcsとラムダはCLRアクション、Funcs、デリゲートタイプ、動的オブジェクトと互換性があります。ただし、一部の呼び出しサイトの変換を除いて、これに関するRubyの構文上の糖衣はほとんどありません。かつて私たちが構文を甘くしたのは.NETイベント用でした。IronRubyでは、RubyブロックをCLRイベントハンドラーとして渡すことができますbutton.on_click {|s,e| ... }

ブロックをCLRメソッドに渡すことができるようにするためのさまざまな方法を試しました。最後の引数が呼び出し可能なオブジェクトであるメソッドを検出するか、特別な名前のパラメーターを許可します。このためにすでに開かれている機能リクエストがあります:http://ironruby.codeplex.com/workitem/4511。貢献したいと思っている人にとっては良い挑戦になるでしょう。

于 2011-05-24T23:47:46.810 に答える
-1

あなたは完全にc#でルビーブロックを使うことができます、実際私は現在生産中のアプリケーションでこれを使いました!方法は次のとおりです。

C#ファイルの場合:

public void BlockTest(dynamic block)
{
Console.WriteLine(block.call("world"));
}

Ironrubyの場合:

#require the assembly
block = Proc.new {|i| "hello " + i }
Blah::Blah.BlockTest block

注:c#4.0でのみテスト済み

于 2010-02-18T16:36:01.213 に答える