0

I am interested to look at the compiler generated code for the using code block which generates try-finally, but I do not see both dotPeek and ILSpy showing this detail. I used ildasm.exe to look at this code block and I see that it has the try-finally block in it but cannot understand it well...so wanted to see if these 2 tools would help.

Any ideas?

UPDATED: So I recently used a struct which implemented IDisposable in my project and was worried if the using code block and struct with IDisposable would cause boxing...but I later found the following article which mentioned that the compiler optimizes for this situation and does not box when trying to call Dispose.

http://ericlippert.com/2011/03/14/to-box-or-not-to-box/

So I was curious to see what kind of code does the compiler generate for my using block.

A simple example repro: enter image description here

Kiran
  • 56,921
  • 15
  • 176
  • 161
  • 2
    Post some example decompiled code! – Matthew Watson Oct 28 '15 at 13:04
  • 2
    ILSpy (and I'm guessing dotPeek also) will recognize the compiler generated `using` statement expansion and reverse it back into a `using` statement. – Damien_The_Unbeliever Oct 28 '15 at 13:14
  • If you're wondering about the IL, see [here](http://weblogs.asp.net/kennykerr/introduction-to-msil-part-5-exception-handling). An MSIL instruction will be generated along the lines of `.try L_000b to L_001d finally handler L_001d to L_0027` along with an an instruction somewhere like `leave.s L_0027`. – Matthew Watson Oct 28 '15 at 13:14
  • Updated with more info. – Kiran Oct 28 '15 at 13:41
  • 1
    Choose IL as the language in ILSpy and it will then show you the raw IL, so nothing is hidden. – Jon Hanna Oct 28 '15 at 14:30

1 Answers1

1

The free JustDecompile tool from Telerik is able to show the details.

Basically (Test being a sample class implementing IDisposable), the compiled version of:

internal class Program
{
    private static void Main(string[] args)
    {
        using (var test = new Test())
        {
            test.Foo();
        }

        Console.ReadLine();
    }
}

is decompiled to:

internal class Program
{
    public Program()
    {
    }

    private static void Main(string[] args)
    {
        Test test = new Test();
        try
        {
            test.Foo();
        }
        finally
        {
            if (test != null)
            {
                ((IDisposable)test).Dispose();
            }
        }
        Console.ReadLine();
    }
}
ken2k
  • 48,145
  • 10
  • 116
  • 176
  • Any reason why `test` is casted to `IDisposable`? One can just call `test.Dispose()` without casting. – Matias Cicero Oct 28 '15 at 13:12
  • @MatiasCicero see 'Remarks' https://msdn.microsoft.com/en-us/library/yh598w02.aspx – sab669 Oct 28 '15 at 13:15
  • @MatiasCicero I assume the compiler do that, so the generated code is the same for both implicit and explicit implementations of `IDisposable` – ken2k Oct 28 '15 at 13:15
  • 1
    @MatiasCicero It's cast in case it's implemented using explicit implementation. – Matthew Watson Oct 28 '15 at 13:15
  • 2
    @MatiasCicero: `Test` might [**shadow**](http://stackoverflow.com/q/673779/87698) `Dispose`. In that case, `test.Dispose()` and `((IDisposable)test).Dispose()` would behave differently. – Heinzi Oct 28 '15 at 13:17