2009-10-06 15 views
8

Non penso sia possibile utilizzare gli operatori come parametri per i metodi in C# 3.0 ma esiste un modo per emulare quello o un po 'di zucchero sintattico che fa sembrare che sia quello che sta succedendo?Operatori come parametri di metodo in C#

Lo chiedo perché ho recentemente implementato the thrush combinator in C# ma mentre traducendo Raganwald's Ruby example

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

che recita "Prendi i numeri da 1 a 100, mantenere quelli dispari, prendere la somma di quelli, e poi rispondere alla quadrato di quel numero. "

Sono rimasto senza parole sul roba Symbol#to_proc. Questo è il &: nello select(&:odd?) e nello inject(&:+) sopra.

risposta

8

Beh, in termini semplici si può semplicemente utilizzare 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 

Questo non è molto eccitante, però. Sarebbe bello avere tutti quei delegati prefabbricati per noi. Naturalmente si potrebbe fare questo con una classe statica:

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 
    } 
} 

Infatti, Marc Gravell ha done something very similar in MiscUtil, se si vuole guardare. È quindi possibile chiamare:

DoSomething(Operator<int>.Plus); 

Non è esattamente bella, ma è il più vicino che è supportato in questo momento, credo.

Temo davvero non capisco la roba Ruby, quindi non posso commentare su questo ...

+0

Ottima risposta, la classe operatore sembra essere più o meno esattamente quello che stavo cercando. Avremo provato più tardi però. –

2

Quello che segue è diretta, letterale (per quanto possibile) C# traduzione:

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

In particolare:

  • blocchi: {||} - Diventa lambda: =>
  • select diventa Where
  • inject diventa Aggregate
  • into diventa una chiamata diretta in un'istanza lambda
+0

Molto bello eccetto che manca il punto del combinatore Thrush che in questo caso è quello di spostare x * x fino alla fine per la leggibilità. Vale comunque un +1. –

+0

Non capisco che per essere il caso - ho appena guardato la traduzione di Scala, che fa la stessa cosa che ho fatto. Detto questo, '.Into()' potrebbe essere banalmente scritto come un metodo di estensione se lo si desidera. –

+0

implementazione Scala di Ghosh è molto bello: (da 1 a 100) .filter (_% 2 = 0!) .foldLeft (0) (+ _ _) .into ((x: Int) = > x * x) –