Как использовать блок IronRuby с методом C # - PullRequest
4 голосов
/ 18 февраля 2010

Я использую 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";

Ответы [ 3 ]

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

Блоки Ruby - это не концепция, понятная c # (или любому другому языку .Net).

Чтобы «передать один» подобному понятию в c # делегата, вы должны «обернуть его» в нечто понятное.

Делая лямбду из блока, она становится чем-то, что вы можете передать коду C # в ожидании делегата или выражения.

Это общая проблема сообщества Alt.Net, даже для таких благословенных языков, как f #, где «указатели на функции» не реализованы как делегаты, а вместо этого выполняются немного по-другому (например, экземпляры FastFunc в f #) для прохождения одного из них. из них что-то вроде вашего примера c # потребовало бы обернуть его в делегат (буквально создавая делегат, вызов которого передает параметры в базовый экземпляр и возвращает результат обратно).

Можно утверждать, что такой перевод был бы лучше, если бы он был автоматическим, но это может привести к сложным и странным крайним случаям или ошибкам, и многие разработчики предпочитают знать, что такая операция переноса произойдет, просто взглянув на код. Также бывает, что не всегда может быть разумное преобразование (или существует более одного), поэтому принятие решения пользователем о том, что происходит, является разумным значением по умолчанию.

1 голос
/ 25 мая 2011

По большей части, IronRuby Procs и lambdas взаимозаменяемы с действиями CLR, функциями, типами делегатов и динамическими объектами. Однако в этом есть немного синтаксического сахара в Ruby, кроме некоторых конверсий сайта вызовов. Однажды место, которое мы подслащали, было синтаксисом для событий .NET; IronRuby позволяет передавать блок Ruby в качестве обработчика событий CLR: button.on_click {|s,e| ... }.

Мы разыграли несколько способов, позволяющих передавать блоки в методы CLR; либо путем обнаружения методов, последний аргумент которых является вызываемым объектом, либо путем разрешения специального именованного параметра. Для этого уже открыт запрос на функцию (хотя и загадочно названный): http://ironruby.codeplex.com/workitem/4511. Было бы хорошим испытанием для всех, кто хочет внести свой вклад.

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

Вы можете полностью использовать блоки ruby ​​в c #, фактически я использовал это в приложении, которое в настоящее время находится в производстве!вот как:

В файле 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

...