Delegates

Multicast

Derive from a base type called MulticastDelegate. As the name suggests, this means delegates can refer to more than one method. The multicast feature is available through the Delegate class’s static Combine method.

    public static Delegate Combine(Delegate a,Delegate b)
    public static Delegate Remove(Delegate source, Delegate value)

Or use addition and subtraction operators, delegate combine=add, remove=subtract {gist}.

Invocation

Although delegates are special types with runtime-generated code, there is ultimately nothing magical about invoking a delegate. The call happens on the same thread, and exceptions propagate through methods that were invoked via a delegate in exactly the same way as they would if the method were invoked directly. Invoking a delegate with a single target method works as though your code had called the target method in the conventional way. Invoking a multicast delegate is just like calling each of its target methods in turn.

    // Invoking each delegate individually
    foreach (Predicate<int> p in userCallbacks.GetInvocationList()) 

    // Dynamically invokes (late-bound) the method represented by the current delegate
    public object DynamicInvoke(params object[] args)

Construction

It’s only necessary in cases where the compiler cannot infer the delegate type.

Implicit delegate construction

// When code refers to a method by name like this, the name is technically called a method group, because multiple overloads may exist for a single name.
Predicate<int> p = IsGreaterThanZero;
// Delegates to static methods in another class
Predicate<int> p2 = Comparisons.IsLessThanZero;

Implicit instance delegate

Refer to an instance method by name from a context in which that method is in scope.

    public class ThresholdComparer {
        public int Threshold { get; set; }
        public bool IsGreaterThan(int value) { return value > Threshold; }
        public Predicate<int> GetIsGreaterThanPredicate() { return IsGreaterThan; }
    }

Explicit instance delegate

Can take any expression that evaluates to an object reference, and then just append .MethodName.

    var zeroThreshold = new ThresholdComparer { Threshold = 0 };
    Predicate<int> greaterThanZero = zeroThreshold.IsGreaterThan;

CreateDelegate

do not necessarily know which method or object you will use until runtime / many overloads There are also overloads that accept the reflection API’s MethodInfo object to identify the method instead of a string.

    var greaterThanZero = (Predicate<int>)Delegate.CreateDelegate(typeof(Predicate<int>), zeroThreshold, "IsGreaterThan");

Conversion

Delegate conversion and contra variance

The type parameters for the function’s parameters are all contravariant. gist

Illegal delegate conversion

The lack of type compatibility between ‘compatible’ delegate types may seem odd, but structurally identical delegate types don’t necessarily have the same semantics.

    Predicate<string> pred = IsLongString;
    Func<string, bool> f = pred; // Will fail with compiler error

anonymous function

As an alternative, use an inline method with a non-void return type. An anonymous method is an inline method defined with the delegate keyword.

    public static int GetIndexOfFirstNonEmptyBin(int[] bins) { return Array.FindIndex( bins, delegate (int value) { return value > 0; } ); }

lambda expression

other form of inline method is called a lambda expression

    return Array.FindIndex( bins, value => value > 0 );

Framework

The angle brackets indicate that this is a generic type with a single contravariant type argument T, and the method signature has a single parameter of that type. You can use the new keyword to create a delegate, it needs a method with a bool return type.

public delegate bool Predicate<in T>(T obj);

public delegate void Action<in T1, in T2 >(T1 arg1, T2 arg2);

public delegate TResult Func<in T1, in T2, out TResult>(T1 arg1, T2 arg2);