2010-02-18 3 views
4

J'utilise IronRuby et essayer de comprendre comment utiliser un bloc avec une méthode C#.Comment utiliser un bloc IronRuby avec une méthode C#

Voici le code de base Ruby je tente d'imiter:

def BlockTest() 
    result = yield("hello") 
    puts result 
end 

BlockTest { |x| x + " world" } 

Ma tentative de faire la même chose avec C# et IronRuby est:

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); 

Le BlockTestClass est:

public class BlockTestClass 
{ 
    public void BlockTest(Func<string, string> block) 
    { 
     Console.WriteLine(block("hello ")); 
    } 
} 

Quand je lance le code C# Je reçois une exception:

nombre incorrect d'arguments (0 pour 1)

Si je change le script IronRuby à ce qui suit cela fonctionne.

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

Mais comment puis-je à travailler avec le script IronRuby d'origine pour que ce soit l'équivalent de mon original exemple Ruby?

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

Répondre

2

Les blocs de Ruby ne sont pas un concept compris par C# (ou l'un des autres langages .Net).

Pour « passer un » au concept similaire en C# du délégué, vous devez « envelopper » dans quelque chose qui est compréhensible.

En faisant un lambda hors du bloc, il devient quelque chose que vous pouvez passer à C# code attendant un délégué ou d'expression. Ceci est un problème courant avec la communauté 'Alt.Net', même pour les langages bénis comme f # où les 'pointeurs de fonctions' ne sont pas implémentés en tant que délégués mais sont légèrement modifiés (instances FastFunc dans f # par exemple) pour passer l'un de ces derniers à quelque chose comme votre C# exemple, il faudrait l'envelopper dans un délégué (créant littéralement un délégué dont l'invocation transmet les paramètres à l'instance sous-jacente et renvoie le résultat arrière). On pourrait argumenter qu'une telle traduction serait plus agréable si elle était automatique, mais cela pourrait conduire à des cas complexes et étranges de bord et de nombreux développeurs préfèrent savoir qu'une telle opération d'encapsulation se fera juste en regardant le code. . Il est également possible qu'il n'y ait pas toujours de conversion raisonnable (ou qu'il en existe plusieurs), ce qui oblige l'utilisateur à décider ce qui se passe est un défaut par défaut.

-1

Vous pouvez tout à fait utiliser des blocs rubis en C#, en fait, je l'ai utilisé cela dans une application qui est actuellement en production! voici comment:

en C# fichier:

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

En IronRuby:

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

Note: testé en C# 4.0 uniquement

+0

C'est la même chose que d'utiliser l'approche lambda. J'essayais de trouver un moyen d'utiliser un bloc de la même manière intuitive que Ruby sans avoir à créer explicitement un objet lambda ou Proc. – sipwiz

1

Pour la plupart, IronRuby PROC et lambdas sont interchangeable avec les actions CLR, les Func, les types de délégué et les objets dynamiques.Cependant, il y a peu de sucre syntaxique Ruby par-dessus, à part quelques conversions de sites d'appel. Une fois que nous avons adouci la syntaxe était pour les événements .NET; IronRuby permet de passer un bloc Ruby en tant que gestionnaire d'événement CLR: button.on_click {|s,e| ... }.

Nous avons joué un tas de façons de permettre aux blocs d'être passés aux méthodes CLR; soit en détectant des méthodes dont le dernier argument est un objet appelable, soit en autorisant un paramètre nommé spécial. Une demande de fonctionnalité (bien que nommée de façon cryptique) est déjà ouverte pour cela: http://ironruby.codeplex.com/workitem/4511. Serait un bon défi pour toute personne désireuse de contribuer.

Questions connexes