2012-07-04 40 views
11

Chỉ cần tự hỏi tại sao Enumerable.Range thực hiện IDisposable.Tại sao Enumerable.Range triển khai IDisposable?

Tôi hiểu tại sao IEnumerator<T> làm, nhưng IEnumerable<T> không yêu cầu.


(tôi phát hiện ra điều này trong khi chơi với .Memoise() thực hiện của tôi, trong đó có tuyên bố như

if (enumerable is IDisposable) 
    ((IDisposable)enumerable).Dispose(); 

trong phương pháp "nguồn xong" của nó mà tôi đã đặt một breakpoint trên ra khỏi tò mò, và được kích hoạt bởi một thử nghiệm.)

+1

http://csharpindepth.com/articles/chapter6/iteratorblockimplementation.aspx –

Trả lời

7

Enumerable.Range sử dụng yield return trong phần thân phương pháp của nó. Tuyên bố yield return sản xuất một loại vô danh mà thực hiện IDisposable, dưới sự kỳ diệu của trình biên dịch, như thế này:

static IEnumerable<int> GetNumbers() 
{ 
    for (int i = 1; i < 10; i += 2) 
    { 
     yield return i; 
    } 
} 

Sau khi được biên soạn, có một lớp lồng nhau vô danh như thế này:

[CompilerGenerated] 
private sealed class <GetNumbers>d__0 
    : IEnumerable<int>, IEnumerable, IEnumerator<int>, IEnumerator, IDisposable 
{ 
    //the implementation 
    //note the interface is implemented explicitly 
    void IDisposable.Dispose() { } 
} 

nên kết quả is a IDisposable. Trong ví dụ này, phương thức Dispose để trống. Tôi nghĩ lý do là không có gì cần phải được xử lý. Nếu bạn yield return loại có chứa tài nguyên không được quản lý, bạn có thể nhận được kết quả biên dịch khác. (KHÔNG CHẮC VỀ nó)

+0

Trình biên dịch thực hiện cả IEnumerable và IEnumerator với cùng một lớp? Hấp dẫn. Tôi sẽ phải suy nghĩ về công việc đó. – Fowl

+0

Ồ, tôi thấy nó ngay bây giờ. Nó sử dụng máy trạng thái của nó để phát hiện nếu GetEnumerator đã được gọi nhiều lần và trả về chính nó nếu nó không có. – Fowl

+0

Điều đó có ý nghĩa, nhưng việc có một phương thức factory trả về một kiểu thực hiện 'IDisposable' khi kiểu trả về của nhà máy không có vẻ là một mẫu chống. Các trình vòng lặp do trình biên dịch tạo ra thông qua 'trả về lợi nhuận 'có thể là các kiểu mà việc bỏ qua mà không bị loại bỏ thực tế sẽ vô hại nếu' GetEnumerator() 'chưa bao giờ được gọi, nhưng một khi' GetEnumerator() 'được gọi, xử lý nói chung là cần thiết . Ngẫu nhiên, gọi 'Dispose' trên một iterator sau khi' GetEnumerable() 'đã được gọi ít nhất một lần sẽ làm mất hiệu lực của điều tra viên đầu tiên mà thôi. – supercat

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