C # foreach hành vi bất ngờ


8

Tại sao trình biên dịch C # cho phép điều này biên dịch và ném ngoại lệ thời gian chạy khi chạy?

class Program
{
   static void Main(string[] args)
   {
      IEnumerable<Test> list = new List<Test>() { new Test() };

      foreach(IDisposable item in list)
      {

      }
   }
}

public class Test
{

}

Điều này không biên dịch với bất kỳ giao diện nào và nó không biên dịch nếu bạn thay thế IDis Dùng bằng lớp cụ thể.


4
Nó biên dịch vì có thể tồn tại trường hợp mà xuất phát từ Testđó làm thực hiện IDisposable. Hiệu quả là foreach cố gắng truyền mọi phần tử vào giao diện và ném ngoại lệ nếu điều này không thành công. Giống như nếu bạn viếtd (IDisposable)currentElement. Tuy nhiên tôi có thể thấy được tại sao nó không nên biên dịch trên lớp cụ thể.
HimBromBeere

Theo fiddle của tôi mà biên dịch tốt: dotnetfiddle.net/3Up9nU
HimBromBeere

3
@HimBromBeere: Vâng, đó là điểm của câu hỏi.
Jon Skeet

bạn có thể chắc chắn rằng mình sẽ không gặp phải ngoại lệ khi sử dụng foreach (IDisposable item in list.OfType<IDisposable>())nhưng tôi đoán đó không phải là vấn đề
Innat3

Câu trả lời:


16

Các foreachvòng lặp có một diễn viên tiềm ẩn trong đó. Nó đại khái như thế này:

using (IEnumerator<Test> iterator = list.GetEnumerator())
{
    while (iterator.MoveNext())
    {
        IDisposable item = (IDisposable) iterator.Current;
        // Body of foreach loop here
    }
}

Quay trở lại trước thế hệ, điều đó thuận tiện hơn nhiều so với việc phải sử dụng mã nguồn. Bây giờ nó không quá quan trọng, nhưng sẽ thật kỳ lạ khi nó không được biên dịch. Lưu ý rằng trình biên dịch sẽ kiểm tra rằng ít nhất là khả thi . Nếu bạn sử dụng foreach (string item in list)nó sẽ không biên dịch, bởi vì Testkhông thể là một string- nhưng Test có thể là một IDisposable, bởi vì nó có thể đề cập đến một thể hiện của một lớp con của Testviệc thực hiện đó IDisposable. Nếu bạn làm cho Testlớp bị niêm phong, nó cũng sẽ không biên dịch ngay cả với IDisposable, bởi vì sau đó một Testthể hiện không thể thực hiện IDisposable.

Về cơ bản, nó sẽ biên dịch nếu một kiểu đúc từ Testloại lặp sẽ biên dịch và sẽ không biên dịch theo cách khác. Nhưng nó sẽ thất bại tại thời gian thực hiện nếu một diễn viên bình thường cũng thất bại tại thời điểm thực hiện.

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.