Friday, October 02, 2009

C# under the covers

In an earlier exploration of debug build code patterns I unearthed bits of debug assistance built into simple field-backed getter properties in C#.

That same pattern -- evaluate to a temporary, and then unconditionally branch to a return -- also shows up in non-property methods that return a constant literal or a field. With purely empty methods, there is no such intermediate value to expose to the debugger, so the method just looks like

.method public hidebysig static void UnitStub() cil managed
{
.maxstack 8
L_0000: nop
L_0001: ret
}
view raw gistfile1.cs hosted with ❤ by GitHub

i.e. a block with a Nop and a Return (with no expression).

The canonical stub left by Visual Studio implementing an interface looks like

public static int ThrowsStub(int left, string mid, object right)
{
throw new NotImplementedException();
}
view raw gistfile1.cs hosted with ❤ by GitHub

which resolves to

.method public hidebysig static int32 ThrowsStub(int32 left, string mid, object right) cil managed
{
.custom instance void .maxstack 8
L_0000: nop
L_0001: newobj instance void [mscorlib]System.NotImplementedException::.ctor()
L_0006: throw
}
view raw gistfile1.cs hosted with ❤ by GitHub

i.e. a block with a Nop and a Throw (with a Construct expression).

Nop and a Throw alone will catch any method that simply throws as its one and only operation (even if the exception is passed in from somewhere else); if you want to determine what is being thrown, then dissecting the expression would be required.

In writing a simple static analysis tool, identifying anything that just throws -- and has no decision making logic -- is sufficient for my purposes; for anyone tempted to put massive lambdas in the throw expression, testing for the Construct may be worthwhile.

No comments :