How to use IronRuby block using C # method

I am using IronRuby and trying to figure out how to use a block using the C # method.

This is the basic Ruby code I'm trying to emulate:

def BlockTest () result = yield("hello") puts result end BlockTest { |x| x + " world" } 

My attempt to do the same with C # and 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 ")); } } 

When I run the C # code, I get an exception:

wrong number of arguments (0 to 1)

If I change the IronRuby script to the following, it will work.

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

But how do I get it to work with the original IronRuby script so that it becomes the equivalent of my original Ruby example?

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

Ruby blocks are not a concept understood by C # (or any other .Net language).

To "convey one" to a similar concept in C # delegate, you must "wrap it" in an understandable way.

Having made a lambda from a block, it will become something that you can pass to C # code that expects a delegate or expression.

This is a common problem with the Alt.Net community, even for blessed languages ​​such as f #, where the "function pointers" are not implemented as delegates, but instead are executed somewhat differently (FastFunc instances in f #, for example) to pass one of them, about the same as your C # example, you need to wrap it in a delegate (literally creating a delegate, the call of which passes parameters to the base instance and returns the result).

It can be argued that such a translation would be better if it were automatic, but this can lead to complex and strange cases or errors of the region, and many developers prefer to know that such a wrapping operation will occur just by looking at the code. It also happens that there can not always be a reasonable transformation (or more than one exists), so making the user decide what is happening is a reasonable default.

+2
source

For the most part, IronRuby Procs and lambdas are interchangeable with CLR actions, Funcs, delegate types, and dynamic objects. However, there is little Ruby syntactic sugar, except for some site conversions. Once upon a time, the place we made sweetened the syntax for .NET events; IronRuby allows you to pass a Ruby block as a CLR event handler: button.on_click {|s,e| ... } button.on_click {|s,e| ... } .

We played a bunch of ways to allow block transfers to CLR methods; either by discovering methods whose last argument is the called object, or by providing a special named parameter. A function request is already open there (albeit with an encrypted name): http://ironruby.codeplex.com/workitem/4511 . It would be a good problem for anyone who would like to contribute.

+1
source

You can make full use of ruby ​​blocks in C #, in fact I used this in an application that currently works! here's how:

In a C # file:

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

At Ironruby:

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

note: checked only in C # 4.0

-1
source

Source: https://habr.com/ru/post/1301688/


All Articles