Reputation: 2595
In C#, how does one create a delegate type that maps delegate types to a delegate type?
In particular, in my example below, I want to declare a delegate Sum
such that (borrowing from mathematical notation) Sum(f,g) = f + g
. I then want to invoke Sum(f,g)
-- such as Sum(f,g)(5)
[this meaning f(5) + g(5)
].
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)
}
}
Upvotes: 5
Views: 2154
Reputation: 1503729
You just need to express the specific types. For example:
Func<Func<int, int>, Func<int, int>>
represents a function which takes a (function converting an int to a second int) and returns a (function converting an int to a second int). Or to take two functions and return a third:
Func<Func<int, int>, Func<int, int>, Func<int, int>>
For example:
Func<Func<int, int>, Func<int, int>> applyTwice = (f => x => f(f(x));
This can be returned generically by a method:
public static Func<Func<T,T>, Func<T,T>> ApplyTwice<T>()
{
return func => x => func(func(x));
}
If you want to sum two functions, you might do:
public static Func<int, int> Sum(Func<int, int> first, Func<int, int> second)
{
return x => first(x) + second(x);
}
Now to apply it:
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
(Untested, but should be okay...)
If you don't have C# 3 and .NET 3.5 available to you, then declare the following delegates:
public delegate TResult Func<TResult>();
public delegate TResult Func<T, TResult>(T arg);
public delegate TResult Func<T1, T2, TResult>(T1 arg1, T2 arg2);
(There's more on my C# Versions page.)
Then you'll need to use anonymous methods, e.g.
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
Upvotes: 14
Reputation: 15555
Like Jon said:
Func<int, int> f = i => i * 2;
Func<int, int> g = i => i * i;
Func<int, int> sum = i => f(i) + g(i);
However, if you'd want to create a Sum method for other types than Func<int,int>, you'd have to go with
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();
}
This works for any type T that defines the "+" operator. Just be careful of the performance penalty you'd get for compiling a lambda expression.
Upvotes: 0