2010-11-10 25 views
8

Bir yenilik olarak, çalışma zamanında oluşturulan hafif koddan IL'nin ne kadar farklı olduğunu görmeye çalışıyorum çünkü VS kodunun VS derleyicisinin oluşturduğu kodu görüyorum, çünkü VS kodunun farklı bir performans profili ile çalışma eğiliminde olduğunu fark ettim. oyuncular gibi şeyler. Bir DynamicMethod'dan IL bytearray'i nasıl alabilirim?

yüzden aşağıdaki kodu :: GetMethodBody görünüşte ifade ağaçları ile üretilen kodun yasadışı operasyondur olarak

Func<object,string> vs = x=>(string)x; 
Expression<Func<object,string>> exp = x=>(string)x; 
var compiled = exp.Compile(); 
Array.ForEach(vs.Method.GetMethodBody().GetILAsByteArray(),Console.WriteLine); 
Array.ForEach(compiled.Method.GetMethodBody().GetILAsByteArray(),Console.WriteLine); 

Maalesef bu bir istisna atar yazdı. Kitaplık biçiminde (ör., Araç bir API olmadığı sürece harici bir araçla değil), hafif kodjen kullanarak kod tarafından oluşturulan koda nasıl bakabilirim?

Düzenleme: hata 5. satırda oluşur, compiled.Method.GetMethodBody() özel durumu atar.

Edit2: Yöntemde bildirilen yerel değişkenlerin nasıl kurtarılacağını bilen var mı? Ya da GetVariables için bir yolu yok mu?

+0

Özel durum hangi satırı atar? İlk Array.ForEach 'a yorum yapabilir ve bunun işe yarayıp yaramadığını görebilir misiniz?GetMethodBody() 'ye yapılan ilk çağrının basitçe başarısız olduğunu, çünkü bu ifadenin IL'ye derlenmediğinden şüpheleniyorum. İkinci aramanın başarısız olması için bir neden göremiyorum. – cdhowie

+0

İlginç bir soru. GetMethodBody çağrısında bir InvalidOperationException ("Nesnenin geçerli durumu nedeniyle geçerli değil") alıyorum. CachedAnonymousDelegate ve Expression gibi bir hayatın nasıl başladığını, davranışınızı Func olarak nasıl etkileyeceğinden emin değilim. Bunu çalışmaya devam edeceğim. – Sorax

+0

Seçilen yanıt tüm vakaları kapsamadığı ve gereksiz yere karmaşık olduğu için değiştirilmelidir. Lütfen [bu cevap] bölümüne bakın (http://stackoverflow.com/a/35711507/521757). – jnm2

cevap

16

Evet, işe yaramıyor, yöntem Reflection.Emit tarafından üretildi. IL, MethodBuilder'ın ILGeneratorunda saklanır. Kazabilirsin ama çok çaresiz olmalısın. İç ve özel üyelere ulaşmak için yansıma gerekiyor.

using System.Linq.Expressions; 
using System.Reflection; 
using System.Reflection.Emit; 
... 

     var mtype = compiled.Method.GetType(); 
     var fiOwner = mtype.GetField("m_owner", BindingFlags.Instance | BindingFlags.NonPublic); 
     var dynMethod = fiOwner.GetValue(compiled.Method) as DynamicMethod; 
     var ilgen = dynMethod.GetILGenerator(); 
     var fiBytes = ilgen.GetType().GetField("m_ILStream", BindingFlags.Instance | BindingFlags.NonPublic); 
     var fiLength = ilgen.GetType().GetField("m_length", BindingFlags.Instance | BindingFlags.NonPublic); 
     byte[] il = fiBytes.GetValue(ilgen) as byte[]; 
     int cnt = (int)fiLength.GetValue(ilgen); 
     // Dump <cnt> bytes from <il> 
     //... 

.NET 4.0 sitesinde ilgen.GetType() kullanmak gerekecektir IL jeneratör değiştirildiği için, DynamicILGenerator türetilen BaseType.GetField (...): Bu .NET 3.5SP1 üzerinde çalıştı. ILGenerator.

+0

Yuck! Çok teşekkürler ama! –

+0

Oh, lanet bu çirkin. İyi iş çıkardın ... ... kod daha güzel olamaz. :( – cdhowie

+0

Sadece denedim, Bu .NET 4'te çalışmıyor gibi görünmüyor. FiBytes'in null olduğunu belirtiyor :( –

0
Sana çağırmalıdır bir yöntem olduğu görülmektedir derine biraz kazmak başardı

kapalı göre Hans passant hazırlık çalışmaları da devam BakeByteArray için aşağıdaki eserlerini ::

var dynMethod = fiOwner.GetValue(compiled.Method) as DynamicMethod; 
var ilgen =dynamicMethod.GetILGenerator(); 
byte[] il = ilgen.GetType().GetMethod("BakeByteArray", BindingFlags.NonPublic | BindingFlags.Instance).Invoke(ilgen, null) as byte[]; 

Bu kesinlikle yardımcı olur denilen ama Henüz işimde yardımcı olacak bir şey olan VariableInfo's'u çözmenin bir yolu yok.

+2

İki kere pişiyorsunuz, muhtemelen yanmıyor mu, emin değil. –

+0

Emin değilim, ancak bu kod tamamen işe yaramaz çünkü ben bu yöntemi kullanarak gerçekçi bir şekilde yaptığım gibi metadataToken'in hiçbir şeyde değersiz bir şey olduğunu anlayamadığım şey, değersiz görünüyor. . –

0

Çözüm. Dinamik yöntem oluşturmak için DynamicILInfo veya ILGenerator'u kullanabilirsiniz, ancak burada listelenen çözümlertüm dinamik yöntemleriyle çalışmaz. IL veya ILGenerator yöntemini oluşturmak için DynamicILInfo yöntemini kullanıp kullanmadığınız, IL bayt kodu DynamicMethod.m_resolver.m_code içinde biter. Her iki yöntemi de kontrol etmeniz gerekmez ve daha az karmaşık bir çözümdür. Daha fazla yardımcı yöntemleri için

public static byte[] GetILBytes(DynamicMethod dynamicMethod) 
{ 
    var resolver = typeof(DynamicMethod).GetField("m_resolver", BindingFlags.Instance | BindingFlags.NonPublic).GetValue(dynamicMethod); 
    if (resolver == null) throw new ArgumentException("The dynamic method's IL has not been finalized."); 
    return (byte[])resolver.GetType().GetField("m_code", BindingFlags.Instance | BindingFlags.NonPublic).GetValue(resolver); 
} 

See this answer ve DynamicMethod belirteç çözünürlük soruna yönelik bir çözüm:

Bu

kullanıyor olmalıdır versiyonudur.

İlgili konular