2009-10-06 29 views
8

No creo que sea posible utilizar operadores como parámetros para los métodos en C# 3.0, pero ¿hay alguna manera de emular ese o algún azúcar sintáctico que parezca que eso es lo que está sucediendo?Operadores como parámetros de método en C#

Lo pregunto porque recientemente he implementado the thrush combinator in C# pero al traducir Raganwald's Ruby example

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

que dice "Toma los números del 1 al 100, a mantener los impares, tomar la suma de esos, y luego responder a la cuadrado de ese número ".

Me quedé corto con las cosas de Symbol#to_proc. Esa es la &: en el select(&:odd?) y el inject(&:+) anterior.

Respuesta

8

Bueno, en términos simples que usted puede simplemente usar una 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 

Eso no es muy interesante sin embargo. Sería bueno tener todos esos delegados preconstruidos para nosotros. Por supuesto que podría hacer esto con una clase estática:

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

De hecho, Marc Gravell tiene done something very similar en MiscUtil, si desea buscar. A continuación, puede llamar a:

DoSomething(Operator<int>.Plus); 

No es exactamente bonita, pero es el más cercano que está soportada por el momento, creo.

Me temo que realmente no entiendo las cosas Ruby, así que no puedo comentar sobre eso ...

+0

excelente respuesta, la clase de operador parece ser casi exactamente lo que estaba buscando. Sin embargo, lo habrá intentado más tarde. –

2

El siguiente es directa, literal (lo más posible) C# Traducción:

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

Específicamente:

  • bloques: {||} - convertido en lambdas: =>
  • select se convierte en Where
  • inject se convierte en Aggregate
  • into se convierte en una llamada directa en una instancia lambda
+0

Muy bueno, excepto que se pierde el punto del combinador Thrush, que en este caso es mover el x * x hasta el final para facilitar la lectura. Vale la pena un +1 de todos modos. –

+0

No me di cuenta de que ese era el caso, solo miré la traducción de Scala, que hace lo mismo que hice. Dicho esto, '.Into()' podría escribirse trivialmente como un método de extensión si se quiere. –

+0

aplicación Scala de Ghosh es muy agradable: (1 a 100) .Filter (_% 2 = 0) .foldLeft (0) (_ _ +) .into ((x: int) = > x * x) –