2010-01-12 41 views
9

Trong công việc của tôi với cây biểu hiện trong một vài ngày nay, tôi bắt gặp một cái gì đó mà tôi thấy khó hiểu; hy vọng ai đó sẽ có thể làm sáng tỏ ở đây.Cách tạo Biểu thức <Func <động, động >> - Hay là một lỗi?

Nếu bạn mã Expression<Func<dynamic, dynamic>> expr1 = x => 2 * x; trình biên dịch sẽ khiếu nại và bạn sẽ không nhận được bất kỳ đâu. Tuy nhiên, nó dường như rằng nếu bạn tạo ra một biểu thức như vậy thông qua một phương pháp thì trình biên dịch có vẻ là hạnh phúc về nó và các ứng dụng kết quả hoạt động. Điều này không có ý nghĩa, vì vậy tôi tự hỏi những gì diễn ra đằng sau tấm màn.

Tôi cho rằng, dưới mui xe, khái niệm được trả về bởi ConvertExpression có lẽ là loại Expression<Func<object, object>>, mà là một loại hợp lệ, nhưng nó câu đố với tôi rằng tôi không thể sử dụng Expression<Func<dynamic, dynamic>> gõ vào một lời tuyên bố và nhưng tôi có thể sử dụng nó là kiểu trả về của một phương thức. Xem ví dụ bên dưới.

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

public class ExpressionExample 
{ 
    public void Main() 
    { 
     // Doesn't compile: 
     //Expression<Func<dynamic, dynamic>> expr1 = x => 2 * x; 

     // Compiles and works - OK 
     Expression<Func<double, double>> expr2 = x => 2 * x; 
     Func<double, double> func2 = (Func<double, double>)expr2.Compile(); 
     Console.WriteLine(func2(5.0).ToString()); // Outputs 10 

     // Compiles and works - ??? This is the confusing block... 
     Expression<Func<dynamic, dynamic>> expr3 = ConvertExpression(expr2); 
     Func<dynamic, dynamic> func3 = (Func<dynamic, dynamic>)expr3.Compile(); 
     Console.WriteLine(func3(5.0).ToString()); // Outputs 10 

     // Side note: compiles and works: 
     Expression<Func<object, object>> expr4 = x => double.Parse(2.ToString()) * double.Parse(x.ToString()); 
     Func<object, object> func4 = (Func<object, object>)expr4.Compile(); 
     Console.WriteLine(func4(5.0).ToString()); // Outputs 10 
    } 

    private Expression<Func<dynamic, dynamic>> ConvertExpression<TInput, TOutput>(Expression<Func<TInput, TOutput>> expression) 
    { 
     Expression<Func<object, TInput>> convertToInput = value => (TInput)value; 
     // The following doesn't compile: var input = Expression.Parameter(typeof(dynamic), "input"); 

     var input = Expression.Parameter(typeof(object), "input");   

     Expression<Func<TOutput, dynamic>> convertToOutput = value => (dynamic)value; 

     var body = Expression.Invoke(convertToOutput, Expression.Invoke(expression, Expression.Invoke(convertToInput, input))); 
     var lambda = Expression.Lambda<Func<dynamic, dynamic>>(body, input); 

     return lambda; 
    } 
} 
+0

Động lực trong cây biểu thức - Giải pháp tại đây: [http://stackoverflow.com/questions/3562088/c-4-dynamic-in-expression-trees](http://stackoverflow.com/questions/3562088/c -4-năng động-trong-biểu hiện-cây) –

Trả lời

13

Tôi cho rằng, dưới mui xe, khái niệm được trả về bởi ConvertExpression có lẽ là loại Expression<Func<object, object>>, mà là một loại hợp lệ

đúng.

Tôi không thể sử dụng Expression<Func<dynamic, dynamic>> nhập tuyên bố và tôi có thể sử dụng nó làm kiểu trả về của phương thức.

Phần này của tuyên bố không chính xác. Như bạn lưu ý trong ví dụ của bạn, nó là hoàn toàn hợp pháp để sử dụng loại đó trong khai báo của một biến địa phương.

Bit không hợp pháp là việc thực hiện thao tác động bên trong lambda đang được chuyển đổi thành loại cây biểu thức. Loại cây biểu thức cụ thể không liên quan; điều quan trọng là hoạt động này là năng động.

+0

Cảm ơn rất nhiều câu trả lời và nhận xét - Điều đó giải quyết được! –

+0

@Eric cơ bản có (vẫn còn?) Không có hỗ trợ cho các hoạt động năng động bên trong lambdas. Có bao giờ không? – Maghis

+1

@Maghis: StackOverflow là một nơi tồi tệ để đặt câu hỏi yêu cầu dự đoán tương lai. Chúng tôi không có kế hoạch cho một tính năng như vậy ngay bây giờ; cho dù chúng ta sẽ trong hai mươi năm tới, làm sao tôi biết? –

3

Lỗi trình biên dịch tôi gặp khi tôi thử mã là "lỗi CS1963: Cây biểu thức có thể không chứa hoạt động động". Tôi đã thay đổi dòng sự cố thành Expression<Func<dynamic, dynamic>> expr1 = x => x; (loại bỏ "thao tác" khỏi lambda) và nó hoạt động! Vì vậy, bạn được phép có động lực trong các biểu thức, nhưng bạn không thể thực sự thực hiện bất kỳ "hoạt động" trên chúng. Không phải là rất hữu ích, tôi biết. Trong thử nghiệm của tôi, thậm chí .ToString() được tính là một hoạt động.

+0

Cảm ơn - Tôi thấy như vậy ... Điều đó làm cho mọi thứ thậm chí còn kỳ lạ hơn tôi nghĩ - Vì vậy, nếu có một số hoạt động, sau đó nó không biên dịch. Tuy nhiên, nếu không có, thì nó sẽ biên dịch. Điều đó không mâu thuẫn với triết lý đằng sau loại hoạt động giải quyết các hoạt động, các lời gọi phương thức, vv trong thời gian chạy? –

+2

Các codegen mà chúng tôi tạo ra cho những hoạt động năng động tại thời gian biên dịch thực hiện ngữ nghĩa động trong thời gian chạy là cực kỳ phức tạp; đủ phức tạp mà không có cách dễ dàng để đại diện cho nó sạch trong một cây biểu thức. Về cơ bản, sự lựa chọn đã xuống đến "không cho phép họ trong cây biểu hiện", hoặc "tàu trễ", hoặc "lỗi tàu". Chúng tôi đã chọn cái cũ. Chúng tôi luôn có thể thêm tính năng này làm tính năng trong các phiên bản sau nếu có đủ nhu cầu; nếu bạn có thể mô tả các kịch bản người dùng hấp dẫn thúc đẩy tính năng này, điều đó sẽ giúp ích khi đến lúc tính ngân sách cho tính năng hoạt động. –

+0

Nếu có ai đó mở một bài đăng kết nối, tôi sẽ bỏ phiếu cho nó. –

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