2009-07-24 7 views
5

En C#, comment créer un type de délégué qui mappe les types de délégué à un type de délégué? En particulier, dans mon exemple ci-dessous, je souhaite déclarer un délégué Sum tel que (empruntant à la notation mathématique) Sum(f,g) = f + g. Je veux ensuite appeler Sum(f,g) - tel que Sum(f,g)(5) [cela signifie f(5) + g(5)].C#: comment créer un type de délégué à partir de types de délégué?

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

Répondre

14

Vous avez juste besoin d'exprimer les types spécifiques. Par exemple:

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

représente une fonction qui prend une (fonction de conversion d'un int vers un second int) et renvoie une (fonction de conversion d'un entier à une seconde int). Ou prendre deux fonctions et retourner une troisième:

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

Par exemple:

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

Cela peut être renvoyé génériquement par une méthode:

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

Si vous voulez résumer deux fonctions , vous pourriez faire:

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

Maintenant, pour l'appliquer:

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 

(non testé, mais devrait être correct ...)


Si vous ne disposez pas C# 3 et .NET 3.5 à votre disposition, puis déclarer la les délégués suivants:

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

(Il y a plus sur mon C# Versions page.)

Ensuite, vous aurez besoin d'utiliser anonymou s méthodes, par ex.

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

Bon sang, vous obtenez une phrase d'une réponse et bam, skeeted encore. –

+0

Jon: Mon logiciel est un peu daté. Est-ce important que j'utilise CLR Version 2.0.50727.42? – JaysonFix

+0

@JaysonFix: Oui, malheureusement, la syntaxe lambda (x => x * 2 par exemple) et les types de délégués Func sont des constructions C# 3/.NET3.5. Faire cela dans .NET2.0 et C# 2 demandera plus d'efforts. –

0

Comme Jon dit:

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

Cependant, si vous voulez créer une méthode Somme pour d'autres types que Func < int, int >, vous auriez à aller avec

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

Cela fonctionne pour tout type T qui définit l'opérateur "+". Faites juste attention à la pénalité de performance que vous auriez pour compiler une expression lambda.

+0

Bien sûr, ceci est spécifique à C# 3.0/.NET 3.5. – Ruben

+0

Je pense que vous voulez dire "types autres que int". –

+0

Func réellement; oublié d'échapper à la < >. – Ruben

Questions connexes