2010-03-03 5 views
6

Chuyển sang biểu thức truy vấn LINQ hoạt động khác nhau tùy thuộc vào cú pháp được sử dụng và tôi tự hỏi tại sao lại xảy ra trường hợp này.LINQ ở đâu từ khóa so với Thông số mở rộng và tham số ở đâu

Hãy nói rằng tôi có chức năng rất chung chung này

private IEnumerable<Company> 
    GetCompanies(Expression<Func<Company, bool>> whereClause) 

Việc thực hiện sau đây làm việc như mong đợi

private IEnumerable<Company> 
    GetCompanies(Expression<Func<Company, bool>> whereClause) 
{ 
    return (from c in _ctx.Companies.Where(whereClause) select c); 
} 

Nhưng thực hiện tiếp theo này không biên dịch (Delegate 'System.Func' không mất 1 đối số)

private IEnumerable<Company> 
    GetCompanies(Expression<Func<Company, bool>> whereClause) 
{ 
    return (from c in _ctx.Companies where whereClause select c); 
} 

Rõ ràng là Tôi chỉ có thể sử dụng cú pháp đầu tiên, nhưng tôi đã tự hỏi tại sao trình biên dịch không xử lý các từ khóa ở đâu giống như phần mở rộng Ở đâu?

Cảm ơn, Thomas

Trả lời

3

Cú pháp cho một biểu thức truy vấn liên quan đến một khoản where được (đơn giản hóa hoàn toàn ngữ pháp)

from identifier in expression where boolean-expression select expression 

whereClause không phải là một biểu thức boolean. Để recitify này, bạn có thể nói

from c in _ctx.Companies where whereClause.Compile()(c) select c; 

Lưu ý rằng nếu whereClause là một Func<Company, bool> bạn có thể nhận được ngay với

from c in _ctx.Companies where whereClause(c) select c; 

Lưu ý rằng

from x in e where f 

được dịch một cách máy móc bởi trình biên dịch thành

(from x in e).Where(x => f) 

Tôi nói bằng máy móc vì nó thực hiện bản dịch này mà không thực hiện bất kỳ phân tích ngữ nghĩa nào để kiểm tra tính hợp lệ của các cuộc gọi phương thức vv.

Đặc biệt,

from c in _ctx.Companies where whereClause select c 

được phiên dịch sang

_ctx.Companies.Where(c => whereClause).Select(c) 

đó rõ ràng là vô nghĩa.

Lý do mà

from c in _ctx.Companies.Where(whereClause) select c 

là legit là vì IEnumerable<Company>.Where có tình trạng quá tải chấp nhận một Func<Company, bool> và có một chuyển đổi ngầm từ một Expression<Func<Company, bool>> đến một Func<Company, bool>.

+0

Nếu bạn chấp nhận Func làm đối số thay vì Expression >, thì bạn có thể đã sử dụng Predicate làm loại tham số. –

+0

Vâng đây là một ví dụ đơn giản chỉ tập trung vào sự khác biệt 'ở đâu'. Lý do cho việc sử dụng biểu thức > là tôi muốn nơi được thực hiện trên cơ sở dữ liệu và không phải trong bộ nhớ. –

0

Sự khác biệt là trong sql như nơi họ hy vọng rằng biểu hiện đánh giá để bool. Nhưng ở phương thức Where, kiểu biểu thức có thể là delegate.

để buộc thứ hai để làm việc bạn có thể thay đổi để whereClause.Compile()(c) hoặc thay đổi thông số để Func<Company, bool> whereClausewhereClause(c)

2

Bạn thực sự có thể rút ngắn toàn bộ điều để:

private IEnumerable<Company> 
    GetCompanies(Expression<Func<Company, bool>> whereClause) 
{ 
    return _ctx.Companies.Where(whereClause); 
} 

Khi bạn sử dụng cú pháp LINQ, các mã trong mệnh đề where được dịch sang một Expression<>, đại diện cho một cây mã. Khi bạn chấp nhận Expression<Func<Customer, bool>>, bạn đang nói rằng phương thức của bạn chấp nhận một cây mã, được chuyển đổi từ mã C# bởi trình biên dịch.

Vì bạn đã có cây mã, bạn phải chuyển nó trực tiếp đến phương thức Where(), thay vì sử dụng cú pháp LINQ.

+0

Có, tôi nhận ra rằng, ví dụ của tôi đã được thực hiện để đánh vần nơi xảy ra sự khác biệt, tức là ở đâu so với .Where. Cảm ơn mặc dù :). –