The question is not so trivial. If you look at the delegate instance
dd
you will find that this is an instance of some… class. This class actually encapsulate a lot of functionality. In particular, it has the container of handlers called "invocation list", accessible through
dd.GetInvocationList()
. This list is use to call all handlers in sequence as a result of invocation and pass the them their own instances of "self" (passed when a handler is added) and calling parameters passed from the invocation call.
The handler is added to the invocation list by "+" (for the first time) and "+=". Is it really so? Not exactly! The delegate instance looses its referential integrity on each "+="!
static void ReportDelegateEquivalence(Delegate left, Delegate right) {
FormatEqual formatEqual = delegate(bool value) { if (value) return string.Empty; else return "NOT"; };
System.Console.WriteLine(
"Delegates are {0} equal, they are referentually {1} equal",
formatEqual(left == right),
formatEqual(object.ReferenceEquals(left, right)));
}
static void TestDelegateEquivalence() {
TestDelegate delegate1 = delegate(string name) { return 1; };
TestDelegate delegate2 = delegate(string name) { return 1; };
ReportDelegateEquivalence(delegate1, delegate2);
delegate1 = delegate2;
ReportDelegateEquivalence(delegate1, delegate2);
delegate2 += delegate(string name) { return 2; };
ReportDelegateEquivalence(delegate1, delegate2);
}
This test shows that the delegate instance does not actually add a new handler. Instead, a brand new delegate instance is created with extended invocation list. So, the delegate instance is
immutable. The purpose is the behavior is improving multithreading support: what is one thread is through the call of invocation while another thread is performing "+="?
Credit to
Nishant Sivakumar how explained the purpose of this feature to me.
[EDIT]
Please see my recent article on the topic:
Dynamic Method Dispatcher[
^]. In particular, see this chapter:
Dynamic Method Dispatcher[
^].
—SA