Delegates in .NET: how are they constructed ?
- by Saulius
While inspecting delegates in C# and .NET in general, I noticed some interesting facts:
Creating a delegate in C# creates a class derived from MulticastDelegate with a constructor:
.method public hidebysig specialname rtspecialname instance
void .ctor(object 'object', native int 'method') runtime managed { }
Meaning that it expects the instance and a pointer to the method. Yet the syntax of constructing a delegate in C# suggests that it has a constructor
new MyDelegate(int () target)
where I can recognise int () as a function instance (int *target() would be a function pointer in C++). So obviously the C# compiler picks out the correct method from the method group defined by the function name and constructs the delegate. So the first question would be, where does the C# compiler (or Visual Studio, to be precise) pick this constructor signature from ? I did not notice any special attributes or something that would make a distinction. Is this some sort of compiler/visualstudio magic ? If not, is the T (args) target construction valid in C# ? I did not manage to get anything with it to compile, e.g.:
int () target = MyMethod;
is invalid, so is doing anything with MyMetod, e.g. calling .ToString() on it (well this does make some sense, since that is technically a method group, but I imagine it should be possible to explicitly pick out a method by casting, e.g. (int())MyFunction. So is all of this purely compiler magic ? Looking at the construction through reflector reveals yet another syntax:
Func CS$1$0000 = new Func(null, (IntPtr) Foo);
This is consistent with the disassembled constructor signature, yet this does not compile!
One final interesting note is that the classes Delegate and MulticastDelegate have yet another sets of constructors:
.method family hidebysig specialname rtspecialname instance
void .ctor(class System.Type target, string 'method') cil managed
Where does the transition from an instance and method pointer to a type and a string method name occur ? Can this be explained by the runtime managed keywords in the custom delegate constructor signature, i.e. does the runtime do it's job here ?