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# 代码时,出现以下异常:

参数数量错误(0 代表 1)

如果我将 IronRuby 脚本更改为以下内容,它将起作用。

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

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

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

3 回答 3

2

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

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

通过从块中制作一个 lambda,它变成了您可以传递给期望委托或表达式的 c# 代码的东西。

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

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

于 2010-02-18T12:15:09.070 回答
1

在大多数情况下,IronRuby Procs 和 lambdas 可以与 CLR Actions、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# 中使用 ruby​​ 块,事实上我已经在当前生产的应用程序中使用了它!方法如下:

在 c# 文件中:

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

在铁红宝石中:

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

注意:仅在 c# 4.0 中测试

于 2010-02-18T16:36:01.213 回答