2011-11-14 31 views
24

Tôi đang cố gắng hiểu AST trong C#. Tôi tự hỏi, chính xác phương pháp Compile() từ ví dụ này là gì.Phương thức Lambda Expression Compile() làm gì?

// Some code skipped  
Expression<Func<string, int, int, string>> data = Expression.Lambda<Func<string, int, int, string>>( 
     Expression.Call(s, typeof(string).GetMethod(“Substring”, new Type[] { typeof(int), typeof(int) }), a, b), 
     s, a, b 
    ); 
Func<string, int, int, string> fun = data.Compile(); 

Để ngăn chặn sự hiểu lầm, tôi hiểu các cấu trúc Expression.LambdaExpression.Call. Điều tôi quan tâm là phương pháp Compile(). Có phải nó bằng cách nào đó tạo ra MSIL thực? Tôi có thể xem MSIL không?

+0

Để nhận được từ một biểu thức cho một đại biểu bạn có thể gọi bạn cần phải gọi 'Biên dịch()' – BrokenGlass

+0

Ok, và những gì đằng sau đại biểu đó? –

+0

Một phương pháp (MethodInfo) – Jeff

Trả lời

44

Tôi quan tâm đến phương pháp Compile(). Có phải nó bằng cách nào đó tạo ra MSIL thực?

Có. Phương thức biên dịch chạy một khách truy cập trên khối cơ thể lambda và tạo IL động cho mỗi biểu thức con.

Nếu bạn quan tâm đến việc học cách tự nhổ IL, hãy xem this "Hello World" example of how to use Lightweight Codegen. (Tôi lưu ý rằng nếu bạn ở vị trí không may khi phải sử dụng Lightweight Codegen trong một appdomain đáng tin cậy một phần thì mọi thứ có thể hơi lạ trong một thế giới với Chế độ hạn chế bỏ qua; xem Shawn Farkas's article về chủ đề này nếu bạn quan tâm.)

Tôi có thể xem MSIL không?

Có, nhưng bạn cần một "trình hiển thị" đặc biệt. Các visualizer tôi đã sử dụng để gỡ lỗi Compile() trong khi tôi đang thực hiện phần của tôi về nó có thể được tải về tại đây:

http://blogs.msdn.com/b/haibo_luo/archive/2005/10/25/484861.aspx

+2

Rất ấn tượng, mặc dù nó làm tôi đau đầu. –

7

Biểu thức thể hiện cấu trúc dữ liệu dưới dạng cây biểu thức - sử dụng Compile() cây biểu thức này có thể được biên dịch thành mã thực thi dưới dạng đại biểu (gọi là "phương thức").

Sau khi biên dịch, bạn có thể thường gọi đại biểu - trong ví dụ của bạn, đại biểu là Func<string,int,int,string>. Cách tiếp cận này có thể cần thiết khi bạn tự động tạo cây biểu thức dựa trên dữ liệu chỉ có sẵn trong thời gian chạy với mục tiêu cuối cùng của việc tạo và thực hiện ủy nhiệm tương ứng.

Bạn không thể thấy "mã" cho người được ủy quyền. Bản thân cây biểu thức mà nó dựa trên là gần nhất với cái đó.

+0

Cảm ơn! Những gì tôi vẫn không hiểu là, làm thế nào các đại biểu có thể được thực hiện. Tôi cho rằng phải có bytecode, một nơi nào đó ... –

+0

Có lẽ off-topic, nhưng tôi tự hỏi những gì các hình phạt hiệu suất là để tạo ra tất cả IL này năng động. –

0

Câu trả lời cho điều này bây giờ là một phần lỗi thời, ở chỗ nó là bây giờ chỉ đôi khi những gì xảy ra.

Việc biên soạn các biểu thức thành IL yêu cầu Reflection.Emit không có sẵn mọi lúc, đặc biệt với AOT. Vì vậy, trong những trường hợp đó thay vì biên dịch sang IL, biểu thức được "biên dịch" thành một danh sách các đối tượng biểu diễn các lệnh. Mỗi lệnh trong số này có phương thức Run khiến cho nó thực hiện hành động thích hợp, làm việc trên một đống giá trị nhiều như IL hoạt động trên một ngăn xếp. Một phương thức gọi Run trên các đối tượng này sau đó có thể được trả lại làm đại biểu.

Thường chạy đại biểu như vậy chậm hơn so với ghi IL, nhưng đó là tùy chọn duy nhất khi biên dịch sang IL không khả dụng và bước biên dịch thường nhanh hơn, vì vậy thường tổng thời gian biên dịch + ít hơn thông dịch viên so với IL cho các biểu thức một lần.

Vì lý do đó, trong.NET Core bây giờ là một quá tải của Compile mà mất một boolean yêu cầu giải thích ngay cả khi biên dịch để IL có sẵn.

Tất cả đều tạo ra sự kết hợp thú vị giữa các ngôn ngữ; Biểu thức chính nó là một ngôn ngữ, lắp ráp được viết bằng C#, nó có thể biên dịch sang IL và các đối tượng lệnh giải nghĩa cấu thành một ngôn ngữ thứ tư.

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