2014-08-29 12 views
6

Giả sử chúng tôi có list.Where(p=>p.Number > n).Select(p=> p.Name).Where(n=> n.StartsWith(a)).ToList(); điều này sẽ được chạy một thuật toán vượt qua hoặc nó sẽ là 3 vượt qua?LINQ có cố gắng giải quyết mọi thứ trong một lần không?

+0

Giả sử chúng tôi có bài kiểm tra trạng thái và sinh viên được yêu cầu giải quyết một tác vụ thuật toán đơn giản có thể được giải quyết qua C# LINQ trong một truy vấn đơn giản, đẹp mắt. Tuy nhiên, nếu họ không thể chứng minh trong chạy trong một vượt qua nó sẽ được coi là giải pháp không tối ưu và sinh viên sẽ nhận được điểm xấu. – Rella

+0

Lưu ý rằng có một câu hỏi tương tự lại Linq2SQL: truy vấn kết quả sẽ được thực hiện bằng cách sử dụng một câu lệnh 'SELECT' duy nhất? Đối với các truy vấn đơn giản như ví dụ của bạn, nếu chúng có thể được chuyển đổi thành truy vấn SQL thì câu trả lời là có. Nhưng một số [phức tạp] (http://stackoverflow.com/q/22816591/256431) [truy vấn] (http://stackoverflow.com/q/12264751/256431) không làm điều này, và tôi không biết nếu bất kỳ đảm bảo nào được đưa ra. –

Trả lời

6

Nó sẽ tạo danh sách trong một lần truyền, do cách LINQ suối dữ liệu.

Ví dụ, thực hiện việc này:

var query = list.Where(p => p.Number > n); 

Điều đó tự nó không nhìn vào bất kỳ của các phần tử của danh sách. Thay vào đó, nó nhớ danh sách bạn đang xem và khi bạn bắt đầu lặp qua query, mỗi khi bạn yêu cầu phần tử tiếp theo, nó sẽ kiểm tra các phần tử của danh sách cho đến khi tìm thấy kết quả khớp - sau đó dừng lại. Ví dụ:

using (var iterator = query.GetEnumerator()) 
{ 
    iterator.MoveNext(); // This will look for the first match 
    Console.WriteLine(iterator.Current); 

    iterator.MoveNext(); // This will continue from just after the first match 
} 

Mỗi phòng trong số các hoạt động làm việc theo cách đó - như vậy theo thời gian bạn đã có:

var query = list.Where(...) 
       .Select(...) 
       .Where(...); 

... khi bạn yêu cầu mục đầu tiên trong vòng query, nó sẽ chuỗi sao lưu (do đó, Where cuối cùng sẽ yêu cầu kết quả của Select, sẽ yêu cầu kết quả của Where đầu tiên, sẽ yêu cầu danh sách này) và tiếp tục cho đến khi kết quả đạt được. Sau đó, khi bạn yêu cầu mục kế tiếp, mà sẽ hỏi kết quả của Select cho mục tiếp theo vv

ToList xây dựng một List<T> từ tất cả các mục trong nguồn của nó, ngay lập tức - đó là háo hức trong ý nghĩa đó (thay vì các toán tử khác ở đây là lười biếng). Nhưng danh sách gốc sẽ vẫn chỉ được lặp lại một lần.

Để biết thêm chi tiết về cách LINQ to Objects hoạt động - bao gồm triển khai mẫu - bạn có thể muốn đọc Edulinq blog series.

8

list sẽ chỉ được lặp lại một lần trong mã đó, không phải 3 lần.

Tất nhiên, nếu bạn muốn kiểm tra nếu bất kỳ truy vấn tùy ý lặp nguồn nhiều lần nó đủ dễ dàng để kiểm tra thực nghiệm, chỉ cần tạo một IEnumerable đó ném một ngoại lệ khi bạn cố gắng để lặp nó nhiều lần:

public static IEnumerable<T> ThereCanBeOnlyOne<T>(this IEnumerable<T> source) 
{ 
    return new SingleEnumerable<T>(source); 
} 

private class SingleEnumerable<T> : IEnumerable<T> 
{ 
    private bool hasRun = false; 
    private IEnumerable<T> wrapped; 
    public SingleEnumerable(IEnumerable<T> wrapped) 
    { 
     this.wrapped = wrapped; 
    } 
    public IEnumerator<T> GetEnumerator() 
    { 
     if (hasRun) 
      throw new InvalidOperationException(
       "Sequence cannot be enumerated multilpe times"); 
     else 
     { 
      hasRun = true; 
      return wrapped.GetEnumerator(); 
     } 
    } 

    IEnumerator IEnumerable.GetEnumerator() 
    { 
     return GetEnumerator(); 
    } 
} 

Bây giờ bạn chỉ có thể viết:

list.ThereCanBeOnlyOne() 
    .Where(p=>p.Number > n) 
    .Select(p=> p.Name) 
    .Where(n=> n.StartsWith(a)) 
    .ToList(); 

Nếu mã ném một ngoại lệ, bạn đã cố gắng để lặp danh sách cơ bản nhiều lần. Nếu không, bạn đã không.

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