2009-07-24 9 views
5

En C#, ¿cómo se crea un tipo de delegado que asigna tipos de delegados a un tipo de delegado? En particular, en mi ejemplo a continuación, deseo declarar un delegado Sum de modo que (tomando prestado de la notación matemática) Sum(f,g) = f + g. Entonces quiero invocar Sum(f,g) - como Sum(f,g)(5) [esto significa f(5) + g(5)].C#: cómo crear un tipo de delegado a partir de tipos de delegados?

class Example 
{ 
delegate int IntToInt (int i) ; 

public static int Double (int i) { return i * 2 ; } 
public static int Square (int i) { return i * i ; } 

delegate IntToInt IntToIntPair_To_IntToInt (IntToInt f, IntToInt g) ; 

public static IntToInt Sum (IntToInt f, IntToInt, g) { return f + g ; } 

public static void Main () 
    { 
    IntToInt DoubleInstance = Double ; 
    IntToInt SquareInstance = Square ; 

    IntToIntPair_To_IntToInt SumInstance = Sum ; 

    System.Console.WriteLine 
      (SumInstance (DoubleInstance, SquareInstance) (5)) ; 
    // should print 35 = 10 + 25 = Double(5) + Square(5) 
    } 
} 

Respuesta

14

Solo necesita expresar los tipos específicos. Por ejemplo:

Func<Func<int, int>, Func<int, int>> 

representa una función que toma una (función de convertir un int a un segundo int) y devuelve un (función de convertir un int a un segundo int). O tomar dos funciones y volver una tercera:

Func<Func<int, int>, Func<int, int>, Func<int, int>> 

Por ejemplo:

Func<Func<int, int>, Func<int, int>> applyTwice = (f => x => f(f(x)); 

Esto puede ser devuelto de forma genérica por un método:

public static Func<Func<T,T>, Func<T,T>> ApplyTwice<T>() 
{ 
    return func => x => func(func(x)); 
} 

Si desea sumar dos funciones , puede hacer:

public static Func<int, int> Sum(Func<int, int> first, Func<int, int> second) 
{ 
    return x => first(x) + second(x); 
} 

ahora para aplicarlo:

Func<int, int> doubler = x => x * 2; 
Func<int, int> squarer = x => x * x; 
Func<int, int> doublePlusSquare = Sum(doubler, squarer); 

Console.WriteLine(doublePlusSquare(5)); // Prints 35 

(no probado, pero debería estar bien ...)


Si usted no tiene C# 3 y .NET 3.5 disponible para usted, a continuación, declarar la siguientes delegados:

public delegate TResult Func<TResult>(); 
public delegate TResult Func<T, TResult>(T arg); 
public delegate TResult Func<T1, T2, TResult>(T1 arg1, T2 arg2); 

(para más información sobre mi C# Versions page.)

a continuación, tendrá que utilizar anonymou s métodos, p.

public static Func<int, int> Sum(Func<int, int> first, Func<int, int> second) 
{ 
    return delegate(int x) { return first(x) + second(x); }; 
} 

Func<int, int> doubler = delegate (int x) { return x * 2; }; 
Func<int, int> squarer = delegate (int x) { return x * x; }; 
Func<int, int> doublePlusSquare = Sum(doubler, squarer); 

Console.WriteLine(doublePlusSquare(5)); // Prints 35 
+0

Maldición, recibes una oración de una respuesta y bam, skeeted nuevamente. –

+0

Jon: Mi software está algo anticuado. ¿Importa que esté usando la versión 2.0.50727.42 de CLR? – JaysonFix

+0

@JaysonFix: Sí, desafortunadamente, la sintaxis lambda (x => x * 2 por ejemplo) y los tipos de delegados Func son construcciones C# 3/.NET3.5. Hacer esto en .NET2.0 y C# 2 requerirá más esfuerzo. –

0

como Jon dijo:

Func<int, int> f = i => i * 2; 
Func<int, int> g = i => i * i; 
Func<int, int> sum = i => f(i) + g(i); 

Sin embargo, si lo desea crear un método de la suma de otros tipos que Func < int, int >, que tendría que ir con

static Func<T, T> Sum<T>(Func<T, T> f, Func<T, T> g) 
{ 
    ParameterExpression p = Expression.Parameter(typeof(T), "i"); 
    Expression<Func<T, T>> sumExpression = 
      Expression.Lambda<Func<T, T>>(
       Expression.Add(
        Expression.Invoke(Expression.Constant(f), p), 
        Expression.Invoke(Expression.Constant(g), p)), 
       p); 
    return sumExpression.Compile(); 
} 

Esto funciona para cualquier tipo T que define el operador "+". Solo tenga cuidado con la penalización de rendimiento que obtendría al compilar una expresión lambda.

+0

Por supuesto, esto es específico de C# 3.0/.NET 3.5. – Ruben

+0

Creo que te refieres a "tipos distintos de int". –

+0

Func actualmente; olvidó escapar del < >. – Ruben

Cuestiones relacionadas