FWIW, the pre-RyuJIT .NET runtime was definitely capable of inlining and devirtualization. I've seen it do the optimization for IDisposable.Dispose calls, off the top of my head. I would expect RyuJIT is capable of doing this in more places.
I don't know if they've ever implemented this for delegates, though.
I don't know if they've ever implemented this for delegates, though.