2011-11-26 34 views
22

Giả sử tôi có một lớp:Tại sao các đối số biểu thức lambda không rõ ràng giữa Func và Biểu thức <Func>?

class MyClass { 
    public int MyMethod(Func<int, int> f) { return 0; } 
    public int MyMethod(Expression<Func<int, int>> f) { return 1; } 
} 

Khi tôi cố gắng gọi phương thức với một biểu thức lambda, tôi nhận được một lỗi biên dịch nói rằng các cuộc gọi là mơ hồ giữa hai định nghĩa chồng:

var myClass = new MyClass(); 
myClass.MyMethod(x => 1 + x); // Error! 

trong khi, tất nhiên, gọi bằng một loại rõ ràng hoạt động tốt:

myClass.MyMethod((Func<int, int>)(x => 1 + x)); // OK, returns 0 
myClass.MyMethod((Expression<Func<int, int>>)(x => 1 + x)); // OK, returns 1 

Cây biểu thức chứa nhiều thông tin hơn (mã thực tế) và tôi có thể đợi nt để sử dụng thông tin này khi có sẵn. Nhưng tôi cũng muốn mã của tôi làm việc với các đại biểu. Thật không may, sự mơ hồ này làm cho nó vì vậy tôi phải tìm một cách khác để phân biệt giữa hai cuộc gọi, mà messes lên một API khác sạch sẽ.

Thông số C# không nói bất cứ điều gì về tình huống cụ thể này, do đó, theo nghĩa này, hành vi không khớp với thông số.

Tuy nhiên, có một đối số được thực hiện rằng cây biểu thức nên được ưu tiên hơn đại biểu. Phương thức Compile hoạt động như một chuyển đổi rõ ràng từ cây biểu thức cho một đại biểu. Cây biểu thức chứa nhiều thông tin hơn và khi bạn biên dịch cho một đại biểu, bạn sẽ mất thông tin đó. Không có chuyển đổi theo hướng khác.

Có bất kỳ lý do nào không thích cây biểu thức không?

+3

Đối số có lợi cho 'Func' là bạn có thể thực hiện trực tiếp mà không phải trải qua giai đoạn khen ngợi tương đối đắt tiền. – Lee

Trả lời

6

Trả lời câu hỏi trên tiêu đề, chúng không rõ ràng vì hệ thống kiểu không có khái niệm "biểu thức lambda". Đó là một tính năng trình biên dịch có thể được chuyển đổi thành một đại biểu hoặc một cây biểu thức, do đó bạn cần phải rõ ràng về loại mà bạn muốn chuyển đổi nó. Hầu hết các lần đích cũng được trình biên dịch suy ra tự động vì ngữ cảnh trong đó biểu thức lambda được sử dụng. Ví dụ, việc sử dụng lambdas trong IEnumerable phương pháp mở rộng so với việc sử dụng lambdas trong IQueryable phương pháp mở rộng.

Bây giờ, để trả lời câu hỏi về lý do tại sao không phải lúc nào cũng thích cây biểu thức, bạn có đối số hiệu suất mà MagnatLU đã nêu.Nếu bạn chấp nhận Expression và sau đó gọi Compile để có thể thực thi nó, sau đó nó sẽ luôn chậm hơn khi so sánh với việc chấp nhận một đại biểu.

Ngoài ra còn có một sự khác biệt ngữ nghĩa giữa hai, một đại biểu chỉ là một cách để thực hiện một số mã trong khi một cây biểu thức là một mô tả của mã thực tế.

Nếu tôi là bạn, tôi sẽ chọn thay đổi tên của phương thức chấp nhận biểu thức cho một cái gì đó phản ánh rõ ràng những gì nó làm thêm cho đại biểu dựa trên một.

+1

Thực tế là một biểu thức lambda có thể được diễn giải theo hai cách không có nghĩa là không thể có một quy tắc để thích cái này hơn cái kia. Vì vậy, tôi không thực sự thích phần đó của câu trả lời của bạn. Phần còn lại là tuyệt vời, mặc dù. Cảm ơn! –

0

Xây dựng và biên dịch biểu thức cây mất thời gian và có thể gây áp lực đáng kể lên GC. Bạn không nên xây dựng và biên dịch biểu thức trong thời gian chạy trừ khi bạn thực sự thực sự phải làm vậy.

Chỉnh sửa: Cũng xin lưu ý rằng không phải mọi biểu thức hoặc phương pháp đều có thể được biểu thị dưới dạng Expression<E>. Func<U, V> chỉ quan tâm đến các tham số 'và kiểu trả về và không có giới hạn như vậy.

2

Trình biên dịch bao giờ biết có nên chọn cây biểu thức hoặc đại biểu không? Đó là quyết định của bạn và không phải của trình biên dịch.

Tất cả các phương thức LINQ cũng cung cấp cả đại biểu và biểu thức, nhưng chúng là các phần mở rộng ở dạng loại mục tiêu.

Enumerable.Where<T>(this IEnumerable<T> en , Func<T,bool> filter) 
Queryable.Where<T>(this IQueryable<T> en , Expression<Func<T,bool>> filter) 

Vì vậy, dựa trên trình biên dịch loại mục tiêu lựa chọn. Trình biên dịch là một chương trình, thực sự đó là máy và hoàn toàn miễn phí, nó không thể đưa ra quyết định giống như con người về những gì có thể tốt hơn, nó chỉ tuân theo các quy tắc và những quy tắc đó cần phải rõ ràng.

+1

Câu hỏi không phải là lý do tại sao trình biên dịch nhãn nó là mơ hồ: đó là bởi vì nó là trong spec bởi thiếu sót. Câu hỏi đặt ra là tại sao các nhà thiết kế ngôn ngữ lại để nó mơ hồ. –

+0

Tại sao không có câu trả lời cụ thể vì mọi hoán vị và kết hợp không thể thiết kế, theo cách này sẽ có nhiều quy tắc như vậy có mức độ ưu tiên thấp và tình huống sử dụng hiếm. Việc đoán và thêm tất cả các quy tắc thiết kế là không thực tế. –

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