Given the following C# code in which the Dispose method is called in two different ways:
class Disposable : IDisposable
{
public void Dispose()
{
}
}
class Program
{
static void Main(string[] args)
{
using (var disposable1 = new Disposable())
{
Console.WriteLine("using");
}
var disposable2 = new Disposable();
try
{
Console.WriteLine("try");
}
finally
{
if (disposable2 != null)
((IDisposable)disposable2).Dispose();
}
}
}
Once compiled using release configuration then disassembled with ildasm, the MSIL looks like this:
.method private hidebysig static void Main(string[] args) cil managed
{
.entrypoint
// Code size 57 (0x39)
.maxstack 1
.locals init ([0] class ConsoleApplication9.Disposable disposable2,
[1] class ConsoleApplication9.Disposable disposable1)
IL_0000: newobj instance void ConsoleApplication9.Disposable::.ctor()
IL_0005: stloc.1
.try
{
IL_0006: ldstr "using"
IL_000b: call void [mscorlib]System.Console::WriteLine(string)
IL_0010: leave.s IL_001c
} // end .try
finally
{
IL_0012: ldloc.1
IL_0013: brfalse.s IL_001b
IL_0015: ldloc.1
IL_0016: callvirt instance void [mscorlib]System.IDisposable::Dispose()
IL_001b: endfinally
} // end handler
IL_001c: newobj instance void ConsoleApplication9.Disposable::.ctor()
IL_0021: stloc.0
.try
{
IL_0022: ldstr "try"
IL_0027: call void [mscorlib]System.Console::WriteLine(string)
IL_002c: leave.s IL_0038
} // end .try
finally
{
IL_002e: ldloc.0
IL_002f: brfalse.s IL_0037
IL_0031: ldloc.0
IL_0032: callvirt instance void [mscorlib]System.IDisposable::Dispose()
IL_0037: endfinally
} // end handler
IL_0038: ret
} // end of method Program::Main
How does a .NET decompiler such as DotPeek or JustDecompile make the difference between using and try...finally?
memberof
, for example - which can be expressed in IL but not C#, so it it sees that: it knows you didn't write it by hand) – Somatoplasm