2011-12-21 28 views
10

Tôi đọc câu trả lời của câu hỏi this giải thích thứ tự của LINQ đối với các phương thức tạo nên sự khác biệt. Câu hỏi của tôi là tại sao?Tại sao thứ tự của LINQ đối tượng phương thức đếm là

Nếu tôi viết một LINQ to SQL truy vấn, nó không quan trọng thứ tự của các LINQ methods- projections ví dụ:

session.Query<Person>().OrderBy(x => x.Id) 
         .Where(x => x.Name == "gdoron") 
         .ToList(); 

Cây biểu thức sẽ được chuyển thành một SQL hợp lý như thế này:

SELECT * 
    FROM  Persons 
    WHERE Name = 'gdoron' 
    ORDER BY Id; 

Khi tôi chạy truy vấn, truy vấn SQL sẽ được tạo theo cây biểu thức bất kể thứ tự của các phương thức lạ đến mức nào.
Tại sao nó không hoạt động giống với LINQ to objects?
khi tôi liệt kê một IQueryable tất cả các phép chiếu có thể được đặt theo thứ tự hợp lý (ví dụ: Thứ tự theo sau ở đâu) giống như trình tối ưu hóa Cơ sở dữ liệu.

+0

Rất gần, có câu trả lời tốt: [không-the-trật tự-of-LINQ chức năng vật chất] (http://stackoverflow.com/questions/7499384/does-the-order-of -linq-functions-matter) – nawfal

Trả lời

14

Tại sao nó không hoạt động theo cách này với LINQ đối tượng?

LINQ to Objects không sử dụng cây biểu thức. Câu lệnh được chuyển trực tiếp thành một loạt các cuộc gọi phương thức, mỗi cuộc gọi chạy như một phương thức C# bình thường.

Như vậy, sau đây trong LINQ to Objects:

var results = collection.OrderBy(x => x.Id) 
        .Where(x => x.Name == "gdoron") 
        .ToList(); 

Gets biến thành phương pháp trực tiếp cuộc gọi:

var results = Enumerable.ToList(
        Enumerable.Where(
        Enumerable.OrderBy(collection, x => x.Id), 
        x => x.Name = "gdoron" 
        ) 
       ); 

Bằng cách nhìn vào các cuộc gọi phương pháp, bạn có thể thấy tại sao đặt vấn đề. Trong trường hợp này, bằng cách đặt OrderBy đầu tiên, bạn đang lồng nó vào cuộc gọi phương thức bên trong. Điều này có nghĩa là toàn bộ bộ sưu tập sẽ được đặt hàng khi số lần trả lại được liệt kê. Nếu bạn đã chuyển đổi thứ tự:

var results = collection 
        .Where(x => x.Name == "gdoron") 
        .OrderBy(x => x.Id) 
        .ToList(); 

Sau đó, kết quả là chuỗi phương pháp chuyển sang:

var results = Enumerable.ToList(
        Enumerable.OrderBy(
        Enumerable.Where(collection, x => x.Name = "gdoron"), 
        x => x.Id 
        ) 
       ); 

này, đến lượt nó, có nghĩa là chỉ có kết quả lọc sẽ cần phải được sắp xếp như OrderBy thực thi.

+0

Cảm ơn! Vậy tại sao LINQ đối tượng không sử dụng cây biểu thức để nâng cao hiệu suất? – gdoron

+0

@gdoron Tại sao nó nâng cao hiệu suất? –

+0

@EtiennedeMartel, (đặt hàng, lọc) => (lọc, đặt hàng) == Hiệu suất mê hoặc ... – gdoron

8

LINQ đối với việc thực hiện trì hoãn của đối tượng hoạt động khác với linq-to-sql's (và EF's).

Với linq-to-objects, chuỗi phương thức sẽ được thực hiện theo thứ tự các phương thức được liệt kê — nó không sử dụng các cây biểu thức để lưu trữ và dịch toàn bộ.

Calling OrderBysau đóWhere với LINQ-to-đối tượng sẽ, khi bạn liệt kê các kết quả, sắp xếp bộ sưu tập, sau đó lọc nó. Ngược lại, lọc kết quả bằng cách gọi tới Wheretrước khi phân loại với OrderBy sẽ, khi bạn liệt kê, lọc đầu tiên, sau đó sắp xếp. Kết quả là trường hợp thứ hai có thể tạo ra sự khác biệt lớn, vì bạn có khả năng sắp xếp ít mục hơn.

+1

LINQ đối với các đối tượng không sử dụng thực thi hoãn lại ... Cho đến khi bạn liệt kê các kết quả, không có quá trình xử lý nào xảy ra trong LINQ đối với các đối tượng. Nó chỉ không sử dụng các cây biểu thức để chuyển đổi toàn bộ chuỗi phương thức thành một hoạt động đơn lẻ, nhưng thay vì trực tiếp thực hiện các phương thức, mỗi phương thức trả về một số đếm được có hiệu quả như được liệt kê. –

+0

@Reed - cảm ơn. Tôi đã biết điều đó - không chắc tại sao tôi lại nghĩ ngớ ngẩn thế. Tôi đã +1 bạn trả lời và sửa lỗi của tôi. –

+1

Điều quan trọng cần biết - đó là một phần lý do tại sao mọi người thường xuyên (mặc dù nó không phải lúc nào cũng tốt) thêm. ToList() - nó buộc một liệt kê, khiến toàn bộ hoạt động thực thi ngay lập tức. Tuy nhiên, bạn có thể kiểm tra điều này một cách dễ dàng - chỉ cần viết collection.OrderBy (...) trên một bộ sưu tập lớn và bỏ qua các kết quả. Bạn sẽ thấy nó gần như không có chi phí thực thi. –

4

Bởi vì, với LINQ cho SQL, ngữ pháp SQL cho lệnh SELECT yêu cầu các mệnh đề khác nhau xảy ra trong một chuỗi cụ thể. Trình biên dịch phải tạo ra SQL đúng ngữ pháp.

Áp dụng LINQ cho các đối tượng trên IEnumerable liên quan đến việc lặp qua IEnumerable và áp dụng chuỗi hành động cho từng đối tượng trong IEnumerable. Thứ tự các vấn đề: một số hành động có thể biến đổi đối tượng (hoặc dòng của các đối tượng chính nó), những người khác có thể ném các đối tượng đi (hoặc tiêm các đối tượng mới vào luồng).

Trình biên dịch không thể tiết lộ ý định của bạn. Nó xây dựng mã làm những gì bạn nói để làm theo thứ tự mà bạn đã nói để làm điều đó.

1

LINQ to Objects không sắp xếp lại để tránh bước chạy theo thời gian để thực hiện điều gì đó cần được tối ưu hóa ở thời gian mã hóa. Các resharpers của thế giới có thể tại một số điểm giới thiệu các công cụ phân tích mã để hút ra các cơ hội tối ưu hóa như thế này, nhưng nó chắc chắn không phải là một công việc cho thời gian chạy.

+2

Điều đó thực sự không đúng. Mặc dù có một mô hình khái niệm về cách truy vấn SELECT thực hiện (ví dụ:tính toán sản phẩm Descartes của tất cả các bảng có liên quan, áp dụng bất kỳ tiêu chí JOIN nào, áp dụng tiêu chuẩn WHERE, thực hiện bất kỳ nhóm nào, áp dụng tiêu chí HAVING, áp dụng bất kỳ ORDER), nhưng trong thế giới thực, nó sẽ rất ngây thơ (và kém hiệu quả) Việc triển khai SQL thực sự hoạt động theo mô hình khái niệm. Vì vậy, miễn là kết quả tương đương, việc triển khai SQL được tự do hành động trên truy vấn khi chúng thấy phù hợp. –

3

Hoàn toàn hợp pháp để sử dụng các tác vụ phụ. Hãy so sánh:

"crabapple" 
    .OrderBy(c => { Console.Write(c); return c; }) 
    .Where(c => { Console.Write(c); return c > 'c'; }) 
    .Count(); 
"crabapple" 
    .Where(c => { Console.Write(c); return c > 'c'; }) 
    .OrderBy(c => { Console.Write(c); return c; }) 
    .Count(); 
+0

thú vị. Cảm ơn! – gdoron

+0

Chỉ để thêm và ngăn người khác tự chụp chân mình. Có tác dụng phụ trên một vị từ hoặc đặc biệt là một so sánh sẽ gây ra hành vi không thể đoán trước. Số lần so sánh được gọi là thậm chí có thể phụ thuộc vào điểm mấu chốt được chọn ngẫu nhiên và thậm chí đối với cùng một thao tác, phương pháp này có thể được gọi nhiều lần. --- Một vị ngữ nói chung là an toàn hơn, vì nó sẽ chạy cho tất cả các mục, cho mỗi mục cho đến khi khớp hoặc một số điều kiện được xác định trước khác. Tuy nhiên nó có thể vẫn không thể đoán trước tùy thuộc vào đầu vào, hoặc thứ tự đầu vào. --- Có lẽ tốt nhất là không có tác dụng phụ. – Aidiakapi

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