2012-01-04 1 views
15

Tôi đang gặp sự cố khi hiểu sự khác biệt giữa cách Biểu thức và Func hoạt động. Vấn đề này bật lên khi ai đó thay đổi một chữ ký phương pháp từ:Bối rối về việc chuyển đối số Biểu thức so với Func

public static List<Thing> ThingList(Func<Thing, bool> aWhere) 

Để

public static List<Thing> ThingList(Expression<Func<Thing, bool>> aWhere) 

nào phá vỡ mã gọi tôi. Mã gọi cũ (mà làm việc) trông như thế này:

 ... 
     object y = new object(); 
     Func<Thing, bool> whereFunc = (p) => p == y; 
     things = ThingManager.ThingList(whereFunc); 

mã mới (không hoạt động) trông như thế này:

 ... 
     object x = new object(); 
     Expression<Func<Thing, bool>> whereExpr = (p) => p == x; 
     things = ThingManager.ThingList(whereExpr); 

này thất bại trong ThingList (...) trên dòng sử dụng biểu thức:

 var query = (from t in context.Things.Where(aWhere) 
     ... 

với lỗi runtime:

Unable to create a constant value of type 'System.Object'. Only primitive types ('such as Int32, String, and Guid') are supported in this context. 

Ví dụ này được giả tạo, nhưng tôi đoán là nó có liên quan đến biến đối tượng địa phương x không được sao chép đúng cách vào biểu thức.

Ai đó có thể giải thích cách xử lý tình huống này nói chung và tại sao Func hoạt động nhưng Expression thì không?

Trả lời

11

Lý do thay đổi gần như chắc chắn là "đẩy" đánh giá vị từ của bạn vào cửa hàng cơ bản, giúp bạn sao lưu số context. Thay vì đưa tất cả Things vào bộ nhớ và sau đó sử dụng Func<Thing,bool> để quyết định cái nào cần giữ lại, tác giả của API đã thay đổi đã quyết định sử dụng IQueryable và cần một Expression<Func<Thing,bool>> cho điều đó.

Bạn đúng về nguồn gốc của lỗi: không giống như các vị từ trong bộ nhớ, IQueryable không thể sử dụng các đối tượng mà nó không biết, ví dụ: các phiên bản tùy ý của object.

Điều bạn cần làm là thay đổi biểu thức để tránh tham chiếu đối tượng của kiểu dữ liệu không được kho lưu trữ dữ liệu đích hỗ trợ (tôi cho rằng biểu thức cuối cùng sẽ trở thành Khung thực thể hoặc ngữ cảnh Linq2Sql). Ví dụ, thay vì nói

object x = new object(); 
Expression<Func<Thing, bool>> whereExpr = (p) => p == x; 
things = ThingManager.ThingList(whereExpr); 

bạn nên nói

Thing x = new Thing {id = 123}; 
Expression<Func<Thing, bool>> whereExpr = (p) => p.id == x.id; 
things = ThingManager.ThingList(whereExpr); 

(cửa hàng ủng hộ của bạn gần như chắc chắn hiểu nguyên)

+0

có, nó làm theo cách của mình vào một khuôn khổ thực thể. Tôi đoán tôi sẽ phải thực hiện hai phương pháp, một cho Expression, và một cho Func để sử dụng khi cần thiết. – Erix

6

Sự khác biệt giữa biểu hiện và Func được mô tả tốt hơn trong các câu trả lời ở đây: Difference between Expression<Func<>> and Func<>

Một cách giải quyết nhanh chóng để làm cho công việc này một lần nữa sẽ được biên dịch biểu thức trở thành một Func.

var query = (from t in context.Things.Where(aWhere.Compile())