Как настроить IlSpy для показа "реального" кода?
В статьях часто пишут, что "такой-то код компилятор разворачивает в такой-то". Например, для замыканий генерируется класс, создается объект этого класса и переменная становится его полем. using разворачивается в try-finally и так далее. Я решил попробовать посмотреть это, поставил IlSpy, написал вот такой код:
static void Main(string[] args)
{
Action print = delegate { };
for (var i = 0; i < 3; i++)
{
var fix = i;
print += () => Console.Write(fix);
}
print();
using (var fs = new FileStream(@"G:\test.txt", FileMode.Open))
{
var canIReadIt = fs.CanRead;
}
}
Но у меня вместо "зазерькалья" получилось практически то же самое, даже банальный using не развернулся, не говоря уж о замыканиях:
private static void Main(string[] args)
{
Action print = delegate
{
};
for (int i = 0; i < 3; i++)
{
int fix = i;
print = (Action)Delegate.Combine(print, (Action)delegate
{
Console.Write(fix);
});
}
print();
using (FileStream fs = new FileStream("G:\\test.txt", FileMode.Open))
{
bool canIReadIt = fs.CanRead;
}
}
В чем подвох? Я ожидал увидеть нечто такое (код взят из статьи, в которой я прочитал про "развертку"):
// Было
public void Run()
{
int e = 1;
Foo(x => x + e);
}
// Компилятор развернул в такое
public void Run()
{
DisplayClass c = new DisplayClass();
c.e = 1;
Foo(c.Action);
}
private sealed class DisplayClass
{
public int e;
public int Action(int x)
{
return x + e;
}
}
Ну а касаемо using что-то вот такое должно было получиться, судя по книге Албахари:
FileStream fs = new FileStream(@"G:\test.txt", FileMode.Open)
try
{
var canIReadIt = fs.CanRead;
}
finally
{
((IDisposable)fs).Dispose();
}
Ответы (2 шт):
Не совсем понятны мне ваши ожидания. Но если вам нужно увидеть сам IL то нажмите сюда 
или уберите галочки тут (View -> Options)
и посмотрите на результат. Думаю вы поймете какой он на самом деле этот код
Попробуй dotPeek.
По умолчанию декомпилирует вот в такое:
using System;
using System.IO;
public class Test
{
private static void Main(string[] args)
{
Action action = (Action) (() => {});
for (int index = 0; index < 3; ++index)
{
int fix = index;
action += (Action) (() => Console.Write(fix));
}
action();
using (FileStream fileStream = new FileStream("G:\\test.txt", FileMode.Open))
{
bool canRead = fileStream.CanRead;
}
}
}
Но после переключения одного чекбокса
получается полный код:
using System;
using System.IO;
using System.Runtime.CompilerServices;
public class Test
{
[CompilerGenerated]
private static Action CS\u0024\u003C\u003E9__CachedAnonymousMethodDelegate2;
private static void Main(string[] args)
{
if (Test.CS\u0024\u003C\u003E9__CachedAnonymousMethodDelegate2 == null)
{
// ISSUE: method pointer
Test.CS\u0024\u003C\u003E9__CachedAnonymousMethodDelegate2 = new Action((object) null, __methodptr(\u003CMain\u003Eb__0));
}
Action action = Test.CS\u0024\u003C\u003E9__CachedAnonymousMethodDelegate2;
for (int index = 0; index < 3; ++index)
{
Test.\u003C\u003Ec__DisplayClass3 cDisplayClass3 = new Test.\u003C\u003Ec__DisplayClass3();
cDisplayClass3.fix = index;
// ISSUE: method pointer
action = (Action) Delegate.Combine((Delegate) action, (Delegate) new Action((object) cDisplayClass3, __methodptr(\u003CMain\u003Eb__1)));
}
action();
using (FileStream fileStream = new FileStream("G:\\test.txt", FileMode.Open))
{
bool canRead = fileStream.CanRead;
}
}
public Test()
{
base.\u002Ector();
}
[CompilerGenerated]
private static void \u003CMain\u003Eb__0()
{
}
[CompilerGenerated]
private sealed class \u003C\u003Ec__DisplayClass3
{
public int fix;
public \u003C\u003Ec__DisplayClass3()
{
base.\u002Ector();
}
public void \u003CMain\u003Eb__1()
{
Console.Write(this.fix);
}
}
}

