A delegate type may contain generic type parameters. For example:
public delegate T Converter<T> (T arg);
With this definition, we can write a generalized method that works on any type:
public class Util { public static void Process<T> (T[] values, Converter<T> t) { for (int i = 0; i < values.Length; i++) values[i] = t (values[i]); } } class Main { static void Main() { int[] values = { 1, 2, 3 }; Util.Process (values, Square); // Hook in Square foreach (int i in values){ Console.Write (i + " "); // 1 4 9 } } static int Square (int x) { return x * x; } }
With generic delegates, we can write a small set of delegate types to cover methods of any return type and any number of arguments.
These delegates are the Func
and Action
delegates, defined in
the System
namespace:
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 can cover almost all methods.
The following code shows how to
use a Func
delegate that takes a single argument of type
T and returns a same-typed value:
public static void Process<T> (T[] values, Func<T,T> transformer) { for (int i = 0; i < values.Length; i++) values[i] = transformer (values[i]); }
The only practical scenarios not covered by these delegates are ref
/out
and pointer
parameters.
Delegate types are all incompatible with each other, even if their signatures are the same.
Multicast delegates are considered equal if they reference the same methods in the same order.