使用IronRuby包装器方法将块放入C#

时间:2010-02-19 00:24:47

标签: c# ironruby

我正在使用IronRuby并尝试无缝地将块传递给C#。这个问题是How to use an IronRuby block in C#的后续问题,表示无法在IronRuby和C#之间传递阻止。

我接下来的问题是,是否有一种方法可以使用Ruby包装器方法实现相同的目标,使块成为lambda或Proc对象并将其传递给C#?

我希望能够做的一些代码如下。代码不起作用,但希望意图足够明确。

string scriptText =
    @"def BlockTest
     result = csharp.BlockTest somehow-pass-the-block ("hello")
     puts result
    end
    BlockTest { |arg| arg + 'world'}";

Console.WriteLine("Compiling IronRuby script.");
ScriptEngine scriptEngine = Ruby.CreateEngine();
ScriptScope scriptScope = scriptEngine.CreateScope();
scriptScope.SetVariable("csharp", new BlockTestClass());
scriptEngine.Execute(scriptText, scriptScope);

C#BlockTest类是:

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

3 个答案:

答案 0 :(得分:2)

块是一个神秘的东西,在CLR中并不存在。但是,Ruby确实有proc,类似于CLR代理。

例如,这应该可以正常工作:

C#:

public class SomeClass {
    public static void Run(Func<int, int> func) { ... }
}

红宝石:

proc = lambda { |i| i + 10 }
SomeClass.Run(proc)

有几种方法可以创建新的过程(许多人更喜欢Proc.new,但它与C#函数的工作方式不同,所以我更喜欢lambda),但重点是:

lambda(和Proc.new)是一个函数 - 您将函数传递给一个块,它会生成一个新的Proc对象来包装该块。

还有一种方法可以在使用&将块传递给函数时将块隐式转换为proc。

红宝石:

def each
  yield 1
end

相同
def each(&block)
  block.call 1
end

&获取已传递给该方法的块(否则会被yield隐式调用)并将其转换为Proc。一旦它是一个proc,你可以传递它,将它粘贴在数组中,或者将它传递给C#。

因此,要调用您的C#方法,您有两个选择:

  1. 创建一个包含块的包装器方法,并使用&将其转换为proc。然后,您可以使用此proc

  2. 调用底层C#方法
  3. 在ruby中使用lambdaProc.new直接创建proc,并将其传递给C#方法。

  4. 示例:

    C#代码(常见):

    public static class MyClass
    {
        public static void Print(Func<int, int> converter)
        {
            Console.WriteLine("1: {0}", converter(1));
        }
    }
    

    Ruby Code 1(包装器):

    class MyClass
      class << self # this is only needed to alias class (static) methods, not for instance methods
        alias_method :original_print, :print
      end
    
      def self.print(&block)
        original_print block
      end
    end
    
    MyClass.print {|i| i * 10}
    

    Ruby Code 2(直接):

    MyClass.print lambda{|i| i * 10}
    

答案 1 :(得分:0)

我不确定完整的答案,但是如果你调用block.to_proc将它转换为可调用的Proc对象,你可能会更进一步。

答案 2 :(得分:0)

我对Func<> - 代表和块或过程没有成功。懒惰地,我在C#中使用了Proc - 类,并使用block.to_proc从Ruby调用它。在C#中,您可以使用Proc.Call并投射您的结果。

已经有一段时间了,也许这已经过时了。