Используйте метод-обертку IronRuby, чтобы получить блок в C # - PullRequest
2 голосов
/ 19 февраля 2010

Я использую IronRuby и пытаюсь придумать способ передачи блока в C #. Этот вопрос является продолжением Как использовать блок IronRuby в C # , который указывает, что блоки не могут быть переданы между IronRuby и C #.

Мой следующий вопрос заключается в том, есть ли способ достичь той же цели с помощью метода-оболочки Ruby, чтобы превратить блок в лямбда или объект 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 "));
    }
}

Ответы [ 3 ]

2 голосов
/ 28 февраля 2010

Блок - загадочная вещь, которой на самом деле нет в CLR. Однако в Ruby есть proc, аналогичный делегатам CLR.

Например, это должно работать нормально:

C #:

public class SomeClass {
    public static void Run(Func<int, int> func) { ... }
}

Ruby:

proc = lambda { |i| i + 10 }
SomeClass.Run(proc)

Существует несколько способов создания новых процедур (многие люди предпочитают Proc.new, но это не совсем работает так же, как функция C #, поэтому я предпочитаю лямбду), но ключевой момент таков:

lambdaProc.new) - это функция - вы передаете функции блок, и она генерирует новый объект Proc, который оборачивает блок.

Существует также способ неявного преобразования блоков в процы при их передаче в функцию с использованием &.

Ruby:

def each
  yield 1
end

совпадает с

def each(&block)
  block.call 1
end

& берет блок, который был передан методу (который в противном случае был бы неявно вызван yield), и преобразует его в Proc. Как только это будет процесс, вы можете передать его, вставить в массив или передать его в C #.

Итак, для вызова вашего метода C # у вас есть две опции:

  1. Создайте метод-обертку, который принимает блок и использует & для преобразования его в процедуру. Затем вы можете вызвать базовый метод C # с помощью этой процедуры

  2. Используйте lambda или Proc.new в ruby ​​для непосредственного создания процедуры и передачи ее методу 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 (direct):

MyClass.print lambda{|i| i * 10}
0 голосов
/ 23 февраля 2010

У меня не было успеха с Func<> -Делегатами и блоками или проками. Лениво я использовал класс Proc в C # и вызывал его из Ruby с помощью block.to_proc. В C # вы можете использовать Proc.Call и привести свой результат.

Это было давно, так что, возможно, это устарело.

0 голосов
/ 19 февраля 2010

Я не уверен в полном ответе, но вы, вероятно, получите больше, если вы позвоните block.to_proc, чтобы преобразовать его в вызываемый объект Proc.

...