2011-01-21 2 views
28

Возможно ли просмотреть код IL, сгенерированный при вызове команды Compile() в дереве выражений? Рассмотрим очень простой пример:Просмотр кода IL, сгенерированного из скомпилированного выражения

class Program 
{ 
    public int Value { get; set; } 

    static void Main(string[] args) 
    { 
     var param = Expression.Parameter(typeof(Program)); 
     var con = Expression.Constant(5); 
     var prop = Expression.Property(param, typeof(Program).GetProperty("Value")); 
     var assign = Expression.Assign(prop, con); 
     Action<Program> lambda = Expression.Lambda<Action<Program>>(assign, param).Compile(); 

     Program p = new Program(); 
     lambda(p); 



     //p.Value = 5; 
    } 
} 

Теперь выражение дерево делает то, что говорит последняя строка Main. Скомпилируйте приложение, затем откройте его в Reflector. Вы можете увидеть код IL p.Value = 5;, который выполняет задание. Но дерево выражений было создано и скомпилировано во время выполнения. Можно ли просмотреть полученный код IL из компиляции?

+0

Вы просто хотите * эквивалентный * IL для того, что вы делаете * * (т.е. значение свойства)? Или есть что-то о выходе 'Expression', которое вас особенно интересует? –

+0

Ничего конкретного. Мне нравится время от времени проверять код IL. Но с выражениями вы можете сделать метод, который не получает никакого ИЛ в скомпилированной сборке. ИЛ, используемый для * создания *, имеет это дерево выражений, но не результат компиляции дерева выражений. Имеет ли это смысл? Это просто любопытство и не служит реальной практической цели, которую я вижу. – Amy

+1

Вы пробовали с помощью великолепного ** LinqPad ** инструмента? http://www.linqpad.net/ С его помощью вы можете отображать сгенерированный код как MSIL и быстро экспериментировать практически с любым ... – AFract

ответ

28

Да! Используйте этот инструмент:

http://blogs.msdn.com/b/haibo_luo/archive/2006/11/16/take-two-il-visualizer.aspx

Это было невероятно полезно, когда я внедрения и отладки Compile, как я уверен, вы можете себе представить.

+3

Эрик, если у вас есть время, вы могли бы воплотить это в более существенный ответ? Связывание только ответов не рекомендуется для переполнения стека. – casperOne

+0

Слишком плохо, что он не подлежит компиляции, существует ли бинарная версия? –

+2

@casperOne: Я призываю вас сделать это. Мне нечего добавить. –

21

Создайте DynamicAssembly, затем DynamicModule, DynamicType и DynamicMethod. Сделайте этот метод общедоступным и статическим и передайте его методу CompileTo() на лямбда. Когда вы устанавливаете флаг сборки как «Сохранить». Затем вызовите метод Save() и передайте путь. Он будет записан на диск. Покройте его в отражателе.

Что-то вроде:

var da = AppDomain.CurrentDomain.DefineDynamicAssembly(
    new AssemblyName("dyn"), // call it whatever you want 
    AssemblyBuilderAccess.Save); 

var dm = da.DefineDynamicModule("dyn_mod", "dyn.dll"); 
var dt = dm.DefineType("dyn_type"); 
var method = dt.DefineMethod(
    "Foo", 
    MethodAttributes.Public | MethodAttributes.Static); 

lambda.CompileToMethod(method); 
dt.CreateType(); 

da.Save("dyn.dll"); 
+0

в случае, если кто-то заинтересован в удалении метода MethodAttributes.Static из метода 'DefineMethod', есть некоторые исследования, которые я получил http://stackoverflow.com/a/3993023/903505 в заключение,' CompileToMethod' работает только со статическими метод – Ariex