简体   繁体   中英

C# : how to create delegate type from delegate types?

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

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, eg

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

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.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM