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?
It doesn't make a difference actually. As Mark says in comments - if you write the same code as compiler would generate for using
- decompiler won't be able to make a difference.
However, many decompilers, including DotPeek, can actually use debugging symbols (.pdb) files to locate the actual source code, and then use actual source code, so that no decompilation happens at all. Also, compiling in Debug mode might affect the pattern too (that is - your attempt to mimic using
statement might have different resulting IL in debug vs release compilations).
To prevent DotPeek from using your real source code files, go to Tools > Options > Decompiler and uncheck "Use sources from symbol files when available". Then compile your code in Release and observe that DotPeek will decompile both statements as using
.
How does a .NET decompiler such as DotPeek or JustDecompile make the difference between using and try...finally?
Decompilers largely work on pattern matching. Generally, the IL is translated into the simplest equivalent representation possible in the target language (in this case, C#). That code model is then passed through a series of transformations that attempt to match up code sequences against well-known patterns. With a debug build of ILSpy, you can actually view the output at different stages of this pipeline.
A decompiler's pipeline may include transforms like a loop rewriter. A loop rewriter might reconstitute for
loops by looking for while
loops that are preceded by a variable initializers and which also contain common iteration statements prior to each back edge. When such a loop is detected, it gets rewritten as a more concise for
loop. It doesn't know that the original code actually contained a for
loop; it's simply trying to find the most concise way to represent the code while maintaining correctness.
In a similar way, a using
rewriter would look for try/finally
blocks where the finally
contains a simple null check and Dispose()
call, then rewrite those as using
blocks, which are more concise while still being correct according to the language spec. The decompiler doesn't know that the code contained a using
block, but since almost no one uses the explicit try/finally
form, the results tend to be consistent with the original source.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With