2009-10-06 11 views
8

Je ne pense pas qu'il soit possible d'utiliser les opérateurs comme paramètres pour les méthodes de C# 3.0, mais y a-t-il un moyen d'émuler le sucre syntaxique qui donne l'impression que c'est ce qui se passe?Les opérateurs en tant que paramètres de méthode en C#

Je demande parce que je a récemment mis en the thrush combinator in C# mais tout en traduisant Raganwald's Ruby example

(1..100).select(&:odd?).inject(&:+).into { |x| x * x } 

qui se lit « Prenez les chiffres de 1 à 100, garder les impairs, prendre la somme de ceux-ci, puis répondre à la carré de ce nombre. "

Je suis tombé court sur les choses Symbol#to_proc. C'est le &: dans le select(&:odd?) et le inject(&:+) ci-dessus.

Répondre

8

Eh bien, en termes simples, vous pouvez simplement utiliser un lambda:

public void DoSomething(Func<int, int, int> op) 
{ 
    Console.WriteLine(op(5, 2)); 
} 

DoSomething((x, y) => x + y); 
DoSomething((x, y) => x * y); 
// etc 

Ce n'est pas très excitant cependant. Ce serait bien que tous ces délégués soient préparés pour nous. Bien sûr, vous pouvez le faire avec une classe statique:

public static class Operator<T> 
{ 
    public static readonly Func<T, T, T> Plus; 
    public static readonly Func<T, T, T> Minus; 
    // etc 

    static Operator() 
    { 
     // Build the delegates using expression trees, probably 
    } 
} 

En effet, Marc Gravell a done something very similar à MiscUtil, si vous voulez regarder. Vous pouvez ensuite appeler:

DoSomething(Operator<int>.Plus); 

Ce n'est pas exactement jolie, mais il est le plus proche qui est pris en charge pour le moment, je crois.

Je crains que je ne comprends vraiment pas les choses Ruby, donc je ne peux pas commenter ça ...

+0

réponse excellente, la classe de l'opérateur semble être à peu près exactement ce que je cherchais. Je l'ai essayé plus tard. –

2

Ce qui suit est directe, littérale (autant que possible) Traduction C#:

(Func<int>)(x => x * x)(
    Enumerable.Range(1, 100) 
     .Where(x => x % 2 == 1) 
     .Aggregate((x, y) => x + y)) 

Plus précisément:

  • blocs: {||} - devenir lambdas: =>
  • select devient Where
  • inject devient Aggregate
  • into devient un appel direct sur une instance lambda
+0

Très beau, sauf qu'il manque le point du combinateur Grive qui dans ce cas est de déplacer le x * x à la fin pour plus de lisibilité. Vaut un +1 de toute façon. –

+0

Je n'avais pas réalisé que c'était le cas - j'ai juste regardé la traduction de Scala, qui fait la même chose que moi. Cela dit, '.Into()' pourrait être trivialement écrit comme une méthode d'extension si désiré. –

+0

mise en œuvre Scala Ghosh est très agréable: (1 à 100) .filter (_% 2 = 0!) .foldLeft (0) (_ + _) .into ((x: Int) = > x * x) –

Questions connexes