With generic delegates, we can create a small set of delegate types to represent methods of any return type and any reasonable number of arguments.
For example, the following delegate can represent any method with one parameter and return declaration.
public delegate R MyDelegate<T> (T arg);
C# defines Func and Action delegates in the System namespace to represent all possible methods.
delegate TResult Func <out TResult> (); delegate TResult Func <in T, out TResult> (T arg); delegate TResult Func <in T1, in T2, out TResult> (T1 arg1, T2 arg2); ... and so on, up to T16 delegate void Action (); delegate void Action <in T> (T arg); delegate void Action <in T1, in T2> (T1 arg1, T2 arg2); ... and so on, up to T16
These delegates are extremely general.
The only practical scenarios not covered by these delegates are ref/out and pointer parameters.
Suppose we have the following code.
using System; delegate T ConverterFunction<T>(T arg); class Util// w ww. j ava2 s. c om { public static void Convert<T>(T[] values, ConverterFunction<T> t) { for (int i = 0; i < values.Length; i++) values[i] = t(values[i]); } } class Test { static void Main() { int[] values = { 1, 2, 3 }; Util.Convert(values, Square); foreach (int i in values) Console.Write(i + " "); } static int Square(int x) => x * x; }
By using the Func delegate, we can rewrite the code as
using System; class Util/*from w w w . j a va2 s .co m*/ { public static void Convert<T>(T[] values, Func<T,T> t) { for (int i = 0; i < values.Length; i++) values[i] = t(values[i]); } } class Test { static int Square(int x) => x * x; static void Main() { int[] values = { 1, 2, 3 }; Util.Convert(values, Test.Square); foreach (int i in values) Console.Write(i + " "); } }
ConverterFunction delegate is replaced by a Func delegate that takes a single argument of type T and returns a same-typed value:
static void Transform<T> (T[] values, Func<T,T> transformer) { for (int i = 0; i < values.Length; i++) values[i] = transformer (values[i]); }