The following syntax creates a delegate
type with name NumberInOutDelegate
, representing a method which takes an int
and returns an int
.
public delegate int NumberInOutDelegate(int input);
This can be used as follows:
public static class Program
{
static void Main()
{
NumberInOutDelegate square = MathDelegates.Square;
int answer1 = square(4);
Console.WriteLine(answer1); // Will output 16
NumberInOutDelegate cube = MathDelegates.Cube;
int answer2 = cube(4);
Console.WriteLine(answer2); // Will output 64
}
}
public static class MathDelegates
{
static int Square (int x)
{
return x*x;
}
static int Cube (int x)
{
return x*x*x;
}
}
The example
delegate instance is executed in the same way as the Square
method. A delegate instance literally acts as a delegate for the caller: the caller invokes the
delegate, and then the delegate calls the target method. This indirection decouples
the caller from the target method.
You can declare a generic delegate type, and in that case you may specify that the type is covariant (out
) or contravariant (in
) in some of the type arguments. For example:
public delegate TTo Converter<in TFrom, out TTo>(TFrom input);
Like other generic types, generic delegate types can have constraints, such as where TFrom : struct, IConvertible where TTo : new()
.
Avoid co- and contravariance for delegate types that are meant to be used for multicast delegates, such as event handler types. This is because concatenation (+
) can fail if the run-time type is different from the compile-time type because of the variance. For example, avoid:
public delegate void EventHandler<in TEventArgs>(object sender, TEventArgs e);
Instead, use an invariant generic type:
public delegate void EventHandler<TEventArgs>(object sender, TEventArgs e);
Also supported are delegates where some parameters are modified by ref
or out
, as in:
public delegate bool TryParser<T>(string input, out T result);
(sample use TryParser<decimal> example = decimal.TryParse;
), or delegates where the last parameter has the params
modifier. Delegate types can have optional parameters (supply default values). Delegate types can use pointer types like int*
or char*
in their signatures or return types (use unsafe
keyword). A delegate type and its parameters can carry custom attributes.