The ildasm shows that a direct call of function is performed with "call method" command, while call through event performed with "callvirt delegatename::Invoke()". May seem that direct call should be faster, but let's consider what is Invoke(). Invoke is not a member of Delegate or MulticastDelegate classes. It's a special method generated by compiler
.method public hidebysig virtual instance void
Invoke(string s) runtime managed
{
}
This method doesn't contain any implementation, that might looks strange. But if we pay attention on "runtime" specificator, magic will dissipates. The "runtime" means that code will be generated at runtime, and as we know, it will happens only once. So theoretically both should be the same in terms of productivity.
As for Jon Skeet's test, I launch it several times and interchange direct call with call with the help of delegate, and didn't get confirmation that delegates improve perfomance. Sometimes delegates won, sometimes direct call won. I think that it's because of GC or something else inside .NET affects test, or just switching processes by Windows.