2010-09-17 26 views
9

Hiện tại tôi đang làm việc với một số thư viện áp dụng thực thi trì hoãn thông qua trình lặp. Trong một số trường hợp, tôi có nhu cầu "chuyển tiếp" trình vòng lặp nhận được một cách đơn giản. I E. Tôi phải lấy ví dụ IEnumerable<T> từ phương thức được gọi và trả lại ngay lập tức.Sự khác biệt chính xác giữa việc trả về một cá thể IEnumerable và câu lệnh trả về lợi nhuận trong C#

Bây giờ câu hỏi của tôi: Có sự khác biệt có liên quan nào giữa việc đơn giản trả về số nhận được IEnumerable<T> hoặc tái sinh nó qua vòng lặp không?

IEnumerable<int> GetByReturn() 
{ 
    return GetIterator(); // GetIterator() returns IEnumerable<int> 
} 
// or: 
IEnumerable<int> GetByReYielding() 
{ 
    for(var item in GetIterator()) // GetIterator() returns IEnumerable<int> 
    { 
     yield return item; 
    } 
} 
+2

Lợi thế của việc tái sinh là gì? Nếu bạn muốn thực hiện một số hành động trên các mục, bạn sẽ không nhận được vòng lặp, phải không? Nếu không, tại sao không sử dụng phiên bản mã ngắn hơn? –

+0

Tôi kết luận từ các thí nghiệm của tôi (và kiểm tra IL), rằng việc thực hiện GetByReYielding() sẽ bị trì hoãn (độc lập với cách GetIterator() hoạt động), nhưng việc thực hiện GetByReturn() thì không. Đó là tất cả. – Nico

Trả lời

1

Không có bất kỳ sự khác biệt có liên quan nào (ngoài có thể là hiệu suất) giữa hai vì bạn không làm bất kỳ điều gì với điều tra từ GetIterator(). Nó sẽ chỉ có ý nghĩa để tái năng suất nếu bạn sẽ làm điều gì đó với điều tra viên, như lọc nó.

1

Tôi không thấy có bất kỳ sự khác biệt nào có liên quan ngoài mã bloating.

3

Chúng khác nhau. Ví dụ, nếu GetIterator() khai báo là:

IEnumerable<int> GetIterator() { 
    List<int> result = new List<int>(); 
    for(int i = 0; i < 1000; i++) { 
     result.Add(i); 
    } 
    return result; 
} 

Nếu bạn không làm lại năng suất, các GetIterator() và vòng lặp đã được thực hiện ngay lập tức. Do đó, câu trả lời tùy thuộc vào cách bạn triển khai GetIterator(). Nếu chắc chắn rằng GetIterator() sẽ sinh lãi, do đó, không có điểm nào sinh lợi cho nó.

+2

Thậm chí nếu anh ta sử dụng một trình lặp, nó vẫn sẽ lặp qua toàn bộ danh sách trước _yield_ đầu tiên. –

0

Có sự khác biệt có liên quan.

Việc thực hiện GetByReYielding() sẽ được thực thi theo cách trì hoãn (vì nó là khối lặp). Nếu bạn đã sử dụng một tham số trong GetByReturn() hoặc GetByReYielding() và kiểm tra tham số đó trong thời gian chạy cho nullity (hoặc đã thực hiện bất kỳ xác thực nào khác), kiểm tra này sẽ được thực hiện ngay lập tức khi GetByReturn() được gọi nhưng không ngay lập tức khi GetByReYielding() được gọi ! Việc xác nhận trong GetByReYielding() sẽ được thực hiện theo cách trì hoãn, khi kết quả được lặp lại. - Đây thường là, "quá muộn". Xem tại đây:

// Checks parameters early. - Fine. The passed argument will be checked directly when 
// GetByReturn() is called. 
IEnumerable<int> GetByReturn(IEnumerable<int> sequence) 
{ 
    if(null == sequence) 
    { 
     throw new ArgumentNullException("sequence"); 
    } 

    return GetIterator(); 
} 
// Checks parameters in a deferred manner. - Possibly not desired, it's "too" late. I.e.     // when the  
// result is iterated somewhere in a completely different location in your code the 
// argument passed once will be checked. 
IEnumerable<int> GetByReYielding(IEnumerable<int> sequence) 
{ 
    if(null == sequence) 
    { 
     throw new ArgumentNullException("sequence"); 
    } 

    for(var item in GetIterator()) 
    { 
     yield return item; 
    } 
} 

Ông Skeet giải thích khái niệm này trong http://msmvps.com/blogs/jon_skeet/archive/2010/09/03/reimplementing-linq-to-objects-part-2-quot-where-quot.aspx. Các toán tử truy vấn chuẩn được cung cấp trong .Net sử dụng các hàm wrapper không hoãn (ví dụ: Where()) kiểm tra các tham số và sau đó gọi hàm lặp lõi (như tôi đã trình bày trong triển khai GetByReturn()).

Tôi hy vọng điều này sẽ hữu ích.

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