2010-11-10 19 views
8

Như một chút mới lạ, tôi đang cố gắng xem IL khác nhau như thế nào từ mã trọng lượng nhẹ được tạo ra khi chạy vs mã được tạo bởi trình biên dịch VS, vì tôi nhận thấy rằng mã VS có xu hướng chạy với một cấu hình hiệu suất khác nhau cho những thứ như phôi.Làm thế nào để tôi nhận được IL bytearray từ một DynamicMethod?

Vì vậy, tôi đã viết đoạn mã sau ::

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); 

Thật không may, điều này ném một ngoại lệ như GetMethodBody là dường như một hoạt động bất hợp pháp trên mã được tạo bởi cây biểu thức. Làm cách nào tôi có thể theo cách thư viện (tức là không có công cụ bên ngoài trừ khi công cụ có API) nhìn vào mã được tạo bằng mã bằng cách sử dụng codegen nhẹ?

Chỉnh sửa: lỗi xảy ra trên dòng 5, biên dịch.Method.GetMethodBody() ném ngoại lệ.

Chỉnh sửa2: Có ai biết cách khôi phục các biến cục bộ được khai báo trong phương pháp không? Hoặc là không có cách nào để GetVariables?

+0

Dòng nào đang ném ngoại lệ? Bạn có thể bình luận ra Array.ForEach đầu tiên và xem liệu nó có hiệu quả không?Tôi nghi ngờ rằng các cuộc gọi đầu tiên để GetMethodBody() là không đơn giản chỉ vì biểu hiện đó đã không được biên dịch để IL. Tôi không thấy lý do tại sao cuộc gọi thứ hai sẽ thất bại. – cdhowie

+0

Câu hỏi thú vị. Tôi nhận được một InvalidOperationException ("Hoạt động không hợp lệ do trạng thái hiện tại của đối tượng") trong cuộc gọi GetMethodBody. Tôi không chắc chắn làm thế nào bắt đầu cuộc sống như một CachedAnonymousDelegate vs Expression sẽ ảnh hưởng đến hành vi của bạn như là một Func. Tôi sẽ tiếp tục làm việc này. – Sorax

+0

Câu trả lời được chọn nên được chuyển vì nó không bao gồm tất cả các trường hợp và phức tạp không cần thiết. Vui lòng xem [câu trả lời này] (http://stackoverflow.com/a/35711507/521757). – jnm2

Trả lời

16

Vâng, không hoạt động, phương pháp được tạo bởi Reflection.Emit. IL được lưu trữ trong bộ xử lý ILGenerator của MethodBuilder. Bạn có thể đào nó ra nhưng bạn phải khá tuyệt vọng. Phản ánh là cần thiết để có được các thành viên nội bộ và tư nhân. Điều này làm việc trên NET 3.5SP1:

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> 
     //... 

On .NET 4.0 bạn sẽ phải sử dụng ilgen.GetType() BaseType.GetField (...) vì các máy phát điện IL đã được thay đổi, DynamicILGenerator, có nguồn gốc từ đâu. ILGenerator.

+0

Yuck! Cảm ơn rất nhiều! –

+0

Ồ, thật đáng xấu hổ. Làm tốt lắm ... đó là một sự xấu hổ mã không thể đẹp hơn. :( – cdhowie

+0

Chỉ cần thử nó, Điều này dường như không làm việc trong .NET 4. nó nói với tôi rằng fiBytes là null: ( –

0

Dựa nghỉ việc Hans passant của tôi đã có thể đào sâu hơn một chút dường như có một phương pháp mà bạn nên gọi, gọi BakeByteArray nên các công việc sau ::

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[]; 

Điều này chắc chắn sẽ giúp, nhưng tôi vẫn không có cách nào để giải quyết VariableInfo's mà chỉ là một cái gì đó mà sẽ giúp đỡ trong công việc của tôi.

+2

Bạn đang nướng nó hai lần Không chắc chắn nếu nó bị đốt cháy, có lẽ không. –

+0

Tôi không chắc chắn, tuy nhiên mã này hoàn toàn vô dụng vì tôi không thể tháo rời cái mà tôi thực hiện bằng cách sử dụng phương pháp này vì tôi không thể nhận được siêu dữ liệu của metadataToken được giải quyết cho bất kỳ điều gì hữu ích vì mô-đun được liệt kê trên điều dường như vô giá trị . –

0

Các giải pháp hiện tại đây không được giải quyết tình hình hiện nay trong .NET 4 rất tốt. Bạn có thể sử dụng DynamicILInfo hoặc ILGenerator để tạo phương pháp động, nhưng các giải pháp được liệt kê ở đây không hoạt động với DynamicILInfo phương pháp động ở tất cả.

Cho dù bạn sử dụng phương pháp tạo ra phương pháp DynamicILInfo IL hoặc phương pháp ILGenerator, mã bytecode IL kết thúc bằng DynamicMethod.m_resolver.m_code. Bạn không cần phải kiểm tra cả hai phương pháp và đó là một giải pháp ít phức tạp hơn.

Đây là phiên bản bạn nên sử dụng:

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 cho các phương pháp helper hơn và một giải pháp cho vấn đề giải quyết thẻ DynamicMethod.

Các vấn đề liên quan