I’m using IronRuby and trying to come up with a seamless to pass a block to C#. This question is a follow on from How to use an IronRuby block in C# which indicates blocks cannot be passed between IronRuby and C#.
My subsequent question is as to whether there’s a way to acheive the same goal using a Ruby wrapper method to make the block into a lambda or Proc object and pass it to C#?
Some code that’s along the lines of what I’d like to be able to do is below. The code doesn’t work but hopefully the intent is clear enough.
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);
The C# BlockTest class is:
public class BlockTestClass
{
public void BlockTest(Func<string, string> block)
{
Console.WriteLine(block("hello "));
}
}
A block is a mysterious thing that doesn’t really exist in the CLR. Ruby does however have a
procwhich is analogous to CLR delegates.For example, this should work fine:
C#:
Ruby:
There are several ways to create new procs (many people prefer
Proc.new, but it doesn’t quite work the same way as a C# function so I prefer lambda), but the key point is this:lambda(andProc.new) is a function – you pass the function a block, and it generates a newProcobject which wraps the block.There is also a way of implicitly converting blocks to procs when they are passed to a function, using
&.Ruby:
is the same as
The
&takes the block which has been passed to the method (which would have otherwise been implicitly called byyield) and converts it into aProc. Once it is a proc, you can pass it around, stick it in arrays, or pass it down to C#.So, to call your C# method, you have two options:
Create a wrapper method which takes the block, and uses
&to convert it to a proc. You can then call the underlying C# method with this procUse
lambdaorProc.newin ruby to create a proc directly, and pass it to the C# method.Examples:
C# Code (common):
Ruby Code 1 (wrapper):
Ruby Code 2 (direct):