2016-01-13 20 views
10

Các compiler-generated implementation của IEnumerator/IEnumerable cho các phương thức yield và getters dường như là một lớp và do đó được phân bổ trên heap. Tuy nhiên, các loại .NET khác chẳng hạn như List<T> đặc biệt trả lại struct các điều tra viên để tránh phân bổ bộ nhớ vô dụng. Từ tổng quan nhanh về C# Trong chiều sâu bài đăng, tôi không thấy lý do nào tại sao điều đó cũng không thể xảy ra ở đây.Tại sao bộ đếm được tạo ra bởi trình biên dịch cho "lợi nhuận" không phải là một cấu trúc?

Tôi có thiếu gì đó không?

+0

Tôi chỉ nhận ra rằng vì kiểu trả về là một giao diện ('IEnumerable' hoặc' IEnumerator'), nó [sẽ được đóng hộp] (http://stackoverflow.com/questions/3032750/) anyway, đúng không? Trong trường hợp này, không thể thay đổi phương thức để trả lại một điều tra được đánh máy rõ ràng (như [Danh sách thực hiện] (https://msdn.microsoft.com/en-us/library/b0yss765 (v = vs.110). aspx))? Vì nó thực hiện các giao diện, tất cả các tham chiếu mã đến nó nên được giữ nguyên. (IIRC, điều này hoạt động vì 'foreach' được [phát hiện bằng mẫu] (https://blogs.msdn.microsoft.com/ericlippert/2011/06/30/following-the-pattern/)). – Lazlo

Trả lời

8

Servy trả lời đúng câu hỏi của bạn - một câu hỏi mà bạn đã trả lời cho mình trong một chú thích:

Tôi chỉ nhận ra rằng kể từ khi kiểu trả về là một giao diện, nó sẽ được đóng hộp dù sao, không biết có đúng?

Phải. Câu hỏi tiếp theo của bạn là:

không thể thay đổi phương thức để trả về một điều tra được đánh máy rõ ràng (như List<T> không)?

Vì vậy, ý tưởng của bạn ở đây là người dùng viết:

IEnumerable<int> Blah() ... 

và trình biên dịch thực sự tạo ra một phương thức trả BlahEnumerable mà là một struct mà thực hiện IEnumerable<int>, nhưng với sự phù hợp GetEnumerator vv method và thuộc tính cho phép tính năng "so khớp mẫu" của foreach để giải phóng quyền anh.

Mặc dù đó là một ý tưởng hợp lý, có những khó khăn nghiêm trọng liên quan khi bạn bắt đầu nói dối về kiểu trả về của một phương thức. Đặc biệt khi nói dối liên quan đến việc thay đổi liệu phương thức trả về một cấu trúc hay một kiểu tham chiếu. Hãy nghĩ đến tất cả những điều không ổn:

  • Giả sử phương pháp này là ảo. Làm thế nào nó có thể được ghi đè? Kiểu trả về của một phương thức ghi đè ảo phải khớp chính xác với phương thức ghi đè. (Và tương tự cho: phương pháp ghi đè phương pháp khác, phương pháp thực hiện phương thức của giao diện, v.v.)

  • Giả sử phương pháp được đưa vào đại biểu Func<IEnumerable<int>>. Func<T> là covariant trong T, nhưng hiệp phương sai chỉ áp dụng cho các đối số kiểu của loại tham chiếu.Mã có vẻ như nó trả về một IEnumerable<T> nhưng trên thực tế nó trả về một kiểu giá trị không tương thích hiệp phương sai với IEnumerable<T>, chỉ phân bổ tương thích.

  • Giả sử chúng tôi có void M<T>(T t) where T : class và chúng tôi gọi M(Blah()). Chúng tôi hy vọng suy ra rằng TIEnumerable<int>, vượt qua kiểm tra ràng buộc, nhưng loại cấu trúc không không vượt qua kiểm tra ràng buộc.

Và cứ tiếp tục như vậy. Bạn nhanh chóng kết thúc trong một tập phim của Công ty Ba (cậu bé tôi đang hẹn hò với bản thân mình ở đây), nơi một lời nói dối nhỏ kết thúc lên thành một thảm họa lớn. Tất cả điều này để tiết kiệm một lượng nhỏ áp lực thu gom. Không đáng.

Tôi lưu ý rằng mặc dù việc triển khai được tạo bởi trình biên dịch không tiết kiệm áp lực thu thập theo một cách thú vị. Số trước tiên thời gian GetEnumerator được gọi trên số đếm được trả về, số tự động chuyển số tự động thành một điều tra viên. Lần thứ hai tất nhiên trạng thái là khác nhau để nó phân bổ một đối tượng mới. Vì kịch bản có khả năng là 99,99% là một chuỗi nhất định được liệt kê chính xác một lần, đây là một khoản tiết kiệm lớn đối với áp lực thu thập.

+0

Cảm ơn bạn đã trả lời kỹ lưỡng! Tôi đang nitpicking vào áp lực bộ sưu tập bởi vì tôi đang làm việc với Unity khủng khiếp của Mono thời gian chạy không phải thế hệ GC, vì vậy tôi đang xem xét phân bổ * rất * chặt chẽ. – Lazlo

6

Lớp đó sẽ chỉ từng được sử dụng thông qua giao diện. Nếu nó là một cấu trúc, nó sẽ được đóng hộp 100% thời gian, làm cho nó ít hơn hiệu quả hơn khi sử dụng một lớp học.

Bạn có thể không không hộp nó, vì nó là, theo định nghĩa, không thể sử dụng các loại tại thời gian biên dịch như nó không tồn tại khi bạn bắt đầu biên dịch mã.

Khi viết triển khai tùy chỉnh IEnumerator, bạn có thể hiển thị loại cơ bản thực tế trước khi biên dịch mã, cho phép nó có khả năng được sử dụng mà không bị đóng hộp.

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