Rất nhiều điều đã được nói trước đây, nhưng trở lại gốc rễ, theo một cách kỹ thuật hơn:
IEnumerable
là một tập hợp các đối tượng trong bộ nhớ mà bạn có thể liệt kê - một chuỗi trong bộ nhớ cho phép lặp lại (làm cho nó dễ dàng trong foreach
vòng lặp, mặc dù bạn chỉ có thể đi theo IEnumerator
). Họ cư trú trong bộ nhớ như là.
IQueryable
là một cây biểu thức sẽ được dịch sang một thứ khác vào một lúc nào đó với khả năng liệt kê kết quả cuối cùng . Tôi đoán đây là điều khiến hầu hết mọi người bối rối.
Họ rõ ràng có ý nghĩa khác nhau.
IQueryable
đại diện cho một cây biểu thức (một truy vấn, đơn giản) sẽ được dịch sang một thứ khác bởi nhà cung cấp truy vấn cơ bản ngay khi các API phát hành được gọi, như các hàm tổng hợp LINQ (Sum, Count, v.v.) hoặc ToList [Array, Dictionary ,. ..]. Và IQueryable
các đối tượng cũng thực hiện IEnumerable
, IEnumerable<T>
để nếu chúng đại diện cho một truy vấn , kết quả của truy vấn đó có thể được lặp lại. Điều đó có nghĩa là IQueryable không phải là truy vấn duy nhất. Thuật ngữ đúng là chúng là cây biểu hiện .
Bây giờ làm thế nào những biểu thức đó được thực thi và những gì chúng chuyển sang tất cả được gọi là nhà cung cấp truy vấn (người thực hiện biểu thức mà chúng ta có thể nghĩ về chúng).
Trong thế giới Entity Framework (là nhà cung cấp nguồn dữ liệu cơ bản bí ẩn hoặc nhà cung cấp truy vấn) IQueryable
được dịch thành các truy vấn T-SQL nguyên gốc . Nhibernate
làm những điều tương tự với họ. Ví dụ, bạn có thể viết một khái niệm của riêng mình theo các khái niệm được mô tả khá rõ trong LINQ: Xây dựng liên kết Nhà cung cấp IQueryable và bạn có thể muốn có API truy vấn tùy chỉnh cho dịch vụ nhà cung cấp cửa hàng sản phẩm của mình.
Về cơ bản, IQueryable
các đối tượng sẽ được xây dựng suốt thời gian dài cho đến khi chúng tôi giải phóng chúng một cách rõ ràng và yêu cầu hệ thống viết lại chúng thành SQL hoặc bất cứ điều gì và gửi chuỗi thực thi để xử lý tiếp theo.
Như thể trì hoãn thực thi, đó là một LINQ
tính năng để giữ sơ đồ cây biểu thức trong bộ nhớ và chỉ gửi nó vào thực thi theo yêu cầu, bất cứ khi nào các API nhất định được gọi theo trình tự (cùng Count, ToList, v.v.).
Việc sử dụng hợp lý cả hai phụ thuộc rất nhiều vào các nhiệm vụ bạn phải đối mặt trong trường hợp cụ thể. Đối với mẫu kho lưu trữ nổi tiếng mà cá nhân tôi chọn để trả về IList
, đó là IEnumerable
trên Danh sách (bộ chỉ mục và tương tự). Vì vậy, lời khuyên của tôi là IQueryable
chỉ sử dụng trong các kho lưu trữ và IEnumerable ở bất kỳ nơi nào khác trong mã. Không nói về mối quan tâm kiểm tra mà IQueryable
phá vỡ và phá hỏng nguyên tắc tách mối quan tâm . Nếu bạn trả lại một biểu thức từ trong kho, người tiêu dùng có thể chơi với lớp kiên trì như họ muốn.
Một bổ sung nhỏ cho mớ hỗn độn :) (từ một cuộc thảo luận trong các bình luận)) Không ai trong số họ là đối tượng trong bộ nhớ vì chúng không phải là loại thực sự, chúng là điểm đánh dấu của một loại - nếu bạn muốn đi sâu. Nhưng nó có ý nghĩa (và đó là lý do tại sao ngay cả MSDN cũng hiểu theo cách này) khi nghĩ về IEnumerables như các bộ sưu tập trong bộ nhớ trong khi IQueryables là cây biểu thức. Vấn đề là giao diện IQueryable kế thừa giao diện IEnumerable để nếu nó đại diện cho một truy vấn, kết quả của truy vấn đó có thể được liệt kê. Phép liệt kê làm cho cây biểu thức được liên kết với một đối tượng IQueryable được thực thi. Vì vậy, trên thực tế, bạn không thể thực sự gọi bất kỳ thành viên IEn nào mà không có đối tượng trong bộ nhớ. Nó sẽ vào trong đó nếu bạn làm, dù sao đi nữa, nếu nó không trống. IQueryables chỉ là truy vấn, không phải dữ liệu.