I was working on fixing some custom static analysis rules here. In one of the rules I check whether a type’s member have XML comments. My rule was reporting a false positive regarding lack of XML comments on the compiler-generated default constructor. Well, we shouldn’t expect the compiler to also push XML comments there, right? 🙂
I poked around to see how I could figure out whether a default constructor was a compiler-generated one, or one explicitly written by the developer. This is what the IL looks like for a developer-created default constructor in C# (notice that I didn’t put any code within the constructor… I just had the simple declaration of an empty constructor):
Next, I removed the constructor, and let the compiler generate one. This is what the IL looks like in such case:
Notice that there are no "nop" opcodes. I though "hey, I can inspect the constructor’s body, and if I don’t find any nop opcode, I assume that’s a compiler-generated constructor!". Made that change to the rule, and it seemed to work like a charm for code written in C#. It did not work for code written in VB, though.
This is what an empty developer-generated constructor looks like in VB:
Notice the nop opcodes in there. Hmm… I guess I can’t rely on that then…
Next, I removed the constructor from the VB code, and this is the IL for the compiler-generated constructor:
Notice that the constructor is decorated with the DebuggerNonUserCode attribute. Well, okay, I kinda like that better. I’ve had my rule changed to test for both scenarios, then; that way I get C# and VB covered. I’ve also improved the rule so that it disregards anything decorated with the DebuggerNonUserCode attribute.
Anyways, I thought it’s interesting that we’re always told that it doesn’t matter what .NET language we write code into, it all comes down to the same IL. Well, not so much. 🙂