- Delegates are type safe reference to methods.
- You can hold address of method in delegate object.
- Although all delegate data types derive indirectly from
System.Delegate
, the C# compiler does not allow you to define a class that derives directly or indirectly from System.Delegate
.
- In other words, the delegate keyword is shorthand for declaring a reference type derived ultimately from
System.Delegate
.
public delegate int MyDelegate(int no1, int no2);
public class MyClass
{
public static int Method1(int no1, int no2) => no1 + no2;
public static int Method2(int no1, int no2) => no1 - no2;
}
- To instantiate a delegate, you need a method that corresponds to the signature of the delegate type itself.
- The name of the methods that implemented the delegate is not important.
MyDelegate delInstance1 = MyClass.Method1;
MyDelegate delInstance2 = MyClass.Method2;
var result1 = delInstance1(5, 3);
var result2 = delInstance2.Invoke(2, 5);
Delegate Data Types
- You can pass in a delegate instance (which is a method) as a parameter to other methods.
- That parameter or data type behaves as a delegate (representative) of a method with common signature.
- When you assign a method to a delegate, the method signature does not have to match the delegate exactly.
- This is called covariance and contravariance.
- Covariance makes it possible that a method has a return type that is more derived than that defined in the delegate.
- Contravariance permits a method that has parameter types that are less derived than those in the delegate type.
public delegate Boolean ComparisonHandler(Int32 first, Int32 val2);
public static Boolean GreaterThan(Int32 first, Int32 second) => first > second;
public static Boolean SmallerThan(Int32 first, Int32 second) => first < second;
public static Int32[] BubbleSort(Int32[] items, ComparisonHandler comparisonMethod)
{
for (var i = items.Length - 1; i >= 0; i--)
for (var j = 1; j <= i; j++)
{
if (comparisonMethod(items[j - 1], items[j]))
{
var temp = items[j - 1];
items[j - 1] = items[j];
items[j] = temp;
}
}
return items;
}
static void Main()
{
var items = new[] { 5, 6, 2, 1, 4, 3 };
foreach (int element in BubbleSort(items, GreaterThan))
Console.WriteLine(element);
foreach (int element in BubbleSort(items, SmallerThan))
Console.WriteLine(element);
}
Delegate Internals
- C# defines all delegates, as derived indirectly from
System.Delegate
.
- C# doesn’t specify the delegate implementation’s class hierarchy.
- .NET’s implementation, however, does derive indirectly from
System.Delegate
.
- In addition to
MethodInfo
, a delegate also needs the instance of the object containing the method to invoke.
- This is the purpose of the second property,
Target
.
- In the case of a static method,
Target
corresponds to the type itself.
- All delegates are immutable.
- “Changing” a delegate involves instantiating a new delegate with the modification included.
- Given that a delegate is a reference type, assigning a local variable and then using that local variable is sufficient for making the null check thread-safe.
- Any calls to
DelegateInstance -= <listener>
will not remove a delegate from the delegate instance.
- Rather, it will assign an entirely new multicast delegate without having any effect on the original multicast delegate.
https://s3-us-west-2.amazonaws.com/secure.notion-static.com/a989400f-2aa0-4aeb-851d-26ecd9b4d49c/Untitled
Closure
- Normally, when control leaves the scope of a variable, the variable is no longer valid.
- When a delegate refers to a local variable and is then returned to the calling method, the delegate has a longer life than the variable.
- To fix this, the compiler generates code that makes the life of the captured variable at least as long as the longest-living delegate.
Delegate Operators
- Use of the assignment operator clears out all previous subscribers and allows you to replace them with new subscribers.
- This is an unfortunate characteristic of a delegate.
- It is simply too easy to mistakenly code an assignment when, in fact, the += operator is intended.
- Both the + and – operators and their assignment equivalents, += and -=, are implemented internally using the static methods
System.Delegate.Combine()
& System.Delegate.Remove()
.