2013-01-07 38 views
20

Tôi có câu hỏi về việc thực hiện hoãn lại và xử lý dữ liệu.Khi sử dụng lợi nhuận trong câu lệnh "đang sử dụng", khi nào Vứt bỏ xảy ra?

Hãy xem xét ví dụ sau:

private IEnumerable<string> ParseFile(string fileName) 
{ 
    using(StreamReader sr = new StreamReader(fileName)) 
    { 
     string line; 
     while((line = sr.ReadLine()) != null) 
     { 
      yield return line; 
     } 
    } 
} 

private void LineReader(string fileName) 
{ 
    int counter = 0; 

    foreach(string line in ParseFile(fileName)) 
    { 
     if(counter == 2) 
     { 
      break; // will this cause a dispose on the StreamReader? 
     } else 
     { 
      Console.WriteLine(line); 
      counter++; 
     } 
    } 
} 

sẽ báo cáo kết quả break ngay lập tức gây ra cho người đọc trong ParseFile để xử lý hoặc là nó vẫn được coi là trong bối cảnh và sẽ khóa các tập tin mở cho đến khi chương trình chính nó là đóng cửa?

+2

Viết ứng dụng bảng điều khiển nhanh và tìm hiểu :) – jjxtra

+0

Xin lưu ý rằng, thay vì sử dụng 'ngắt' khi bộ đếm truy cập hai, chỉ cần thêm' Take (2) 'vào cuối' ParseFile'. – Servy

+1

Chọn cuốn sách "C# in Depth" của Jon Skeet nếu bạn muốn có một lời giải thích thực sự tốt về những gì xảy ra trong các khối lặp, hoặc chỉ xem xét thông số ngôn ngữ, như ông thường gợi ý. –

Trả lời

16

Vì vậy, chúng tôi có một số vấn đề riêng biệt đang diễn ra tại đây.

Trước hết, xử lý using trong khối lặp. IEnumerator mở rộng IDisposable. Mã tạo khối lặp thực sự đủ mạnh để bất kỳ khối thử/cuối cùng nào (kết quả là using trong khối try/finally được tạo) kết quả trong nội dung của khối finally được gọi theo phương pháp Dispose của điều tra viên, nếu không đã được gọi. Vì vậy, miễn là điều tra viên được xử lý, nó sẽ không bị rò rỉ StreamReader.

Vì vậy, bây giờ chúng tôi tự hỏi nếu điều tra viên được xử lý. Tất cả các câu hỏi foreach sẽ gọi số Dispose trên điều tra viên (nếu nó thực hiện IDisposable). Họ làm như vậy ngay cả khi bạn thoát bằng cách sử dụng tuyên bố break hoặc return cũng như khi kết thúc bình thường.

Vì vậy, bạn có thể chắc chắn rằng trong mọi trường hợp, tài nguyên sẽ không bị rò rỉ, chặn các trường hợp không có gì có thể được ngăn chặn rò rỉ (tức là ai đó gỡ máy).

+0

Nó phức tạp hơn một chút. Trong trường hợp của OP, trình vòng lặp sẽ loại bỏ hoàn toàn bởi vì câu lệnh break. Nhưng cuộc gọi tới ParseFile tạo ra một tham chiếu đến StreamReader bên trong một 'cục bộ đang sử dụng' mà bây giờ đã biến mất khỏi phạm vi. Tôi nghĩ rằng nó xếp hàng trên hàng đợi finalizer và xử lý khi thu thập? – n8wrl

+3

@ n8wrl Không, điều đó không đúng. Khi 'IEnumerator' được xử lý bởi vòng lặp' foreach', nó sẽ gọi dispose trên 'StreamReader' (giả sử nó nằm bên trong' using' tại thời điểm đó). Đó là cách các khối lặp được thực hiện; để làm điều này có thể. – Servy

+0

Tôi đoán chúng ta nên lấy lời khuyên của PsychoDad và thử nó vì nó sẽ rất tuyệt nếu đó là cách nó hoạt động! – n8wrl