如何使用C#方法使用IronRuby块

我正在使用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 block) { Console.WriteLine(block("hello ")); } } 

当我运行C#代码时,我得到一个例外:

参数个数错误(0表示1)

如果我将IronRuby脚本更改为以下内容,则可以正常工作。

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

但是如何让它与原始的IronRuby脚本一起使用,以便它等同于我原来的Ruby示例?

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

Ruby的块不是c#(或任何其他.Net语言)理解的概念。

要在委托的c#中“传递一个”类似的概念,你必须将它“包装”在可理解的东西中。

通过将lambda从块中取出,它可以成为可以传递给期望委托或表达式的c#代码的东西。

这是’Alt.Net’社区的一个常见问题,即使对于像f#这样的祝福语言,其中’函数指针’没有实现为委托,而是略有不同(例如f#中的FastFunc实例)将其中一个传递给类似于你的c#例子需要将它包装在一个委托中(字面上创建一个委托,其调用将参数传递给底层实例并返回结果)。

有人可能会争辩说,如果它是自动的,这种翻译会更好,但这样做会导致复杂和奇怪的边缘情况或错误,许多开发人员更愿意知道这样的包装操作只会通过查看代码来实现。 情况也可能并非总是存在合理的转换(或存在多个转换),因此使用户决定发生的情况是合理的默认值。

在大多数情况下,IronRuby Procs和lambdas可与CLR Actions,Funcs,委托类型和动态对象互换。 然而,除了一些呼叫站点转换之外,除此之外几乎没有Ruby语法糖。 有一次,我们确实提高了.NET事件的语法; IronRuby允许将Ruby块作为CLR事件处理程序传递: button.on_click {|s,e| ... } button.on_click {|s,e| ... }

我们已经玩弄了许多方法来允许块传递给CLR方法; 通过检测最后一个参数是可调用对象的方法,或者通过允许特殊的命名参数。 有一个function请求(虽然以密码命名)已经打开了: http : //ironruby.codeplex.com/workitem/4511 。 对愿意贡献的人来说,这将是一个很好的挑战。

你可以在c#中完全使用ruby块,事实上我已经在目前正在生产的应用程序中使用了它! 这是如何:

在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中测试过