我正在使用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 "));
}
}
答案 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#方法,您有两个选择:
创建一个包含块的包装器方法,并使用&
将其转换为proc。然后,您可以使用此proc
在ruby中使用lambda
或Proc.new
直接创建proc,并将其传递给C#方法。
示例:
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
并投射您的结果。
已经有一段时间了,也许这已经过时了。