2012-05-17 37 views
7

Nếu tôi có đoạn mã sau:Nếu ngoại lệ được ném vào Danh sách <T> .ForEach, dừng lặp lại có lặp lại không?

List<MyClass> list = GetList(); 
list.ForEach(i => i.SomeMethod()); 

và giả sử SomeMethod() ném một ngoại lệ. ForEach có tiếp tục lặp lại hay không chỉ dừng lại ở đó?

Nếu nó chấm dứt, có cách nào để nhận phần còn lại của các mục trong bộ sưu tập để chạy các phương pháp của họ không?

Trả lời

13

Có, nếu ngoại lệ được ném, vòng lặp sẽ thoát. Nếu bạn không muốn hành vi đó, bạn nên đặt xử lý ngoại lệ vào đại biểu của bạn. Bạn thể dễ dàng tạo ra một phương pháp wrapper cho việc này:

public static Action<T> SuppressExceptions<T>(Action<T> action) 
{ 
    return item => 
    { 
     try 
     { 
      action(item); 
     } 
     catch (Exception e) 
     { 
      // Log it, presumably 
     } 
    }; 
} 

Thành thật mà nói, tôi sẽ cố gắng để tránh điều này nếu có thể. Thật khó chịu khi bắt được tất cả ngoại lệ như vậy. Nó cũng không ghi lại các mục không thành công, hoặc các trường hợp ngoại lệ, vv Bạn thực sự cần suy nghĩ về các yêu cầu của mình chi tiết hơn:

  • Bạn có cần thu thập các mục không thành công không?
  • Bạn có cần thu thập ngoại lệ không?
  • Bạn muốn bắt ngoại lệ nào?

Nó gần như chắc chắn sẽ sạch hơn để tạo ra một phương pháp riêng biệt sử dụng vòng lặp foreach bình thường thay thế, xử lý lỗi và thu thập lỗi khi nó đi. Cá nhân tôi thường thích sử dụng foreach hơn ForEach - bạn có thể đọc Eric Lippert's thoughts on this too.

+0

tôi đã cập nhật tiêu đề câu hỏi của mình, cảm ơn jon – Jason

+0

@ Jason: Righto - sẽ loại bỏ câu đầu tiên đó. Đã chỉnh sửa câu trả lời của tôi ... –

+0

cảm ơn bạn vì câu trả lời rất tốt, suy nghĩ rất thông tin này. – Jason

3

Nó sẽ gây ra lỗi. Bạn cũng đang trên đường thực hiện lại foreach. Làm thế nào về chỉ:

foreach (var item in list) 
{ 
    try 
    { 
     // dangerous thing with item 
    } 
    catch (Exception e) 
    { 
     // how do you want to log this? 
    } 
} 

Điều này có lợi ích khi làm việc trong hầu hết các phiên bản .NET và rõ ràng là có hiệu quả phụ. Tất nhiên, bạn có thể đặt mã này trực tiếp trong đại biểu ForEach, nhưng tôi sẽ chỉ đề nghị rằng nếu nó sẽ là một phương thức (chứ không phải là hàm lambda).


Một lựa chọn hợp lý là tạo ra ForEachWithCatch phần mở rộng của riêng bạn mà bắt tất cả các trường hợp ngoại lệ và gửi chúng trở lại cho người gọi:

public static IEnumerable<Tuple<T,Exception>> ForEachWithCatch<T>(this IEnumerable<T> items, Action<T> action) 
{ 
    var exceptions = new List<Tuple<T,Exception>>(); 

    foreach(var item in items) 
    { 
     try 
     { 
      action(item); 
     } 
     catch(Exception e) 
     { 
      exceptions.Add(Tuple.Create(item, e)); 
     } 
    } 

    return exceptions; 
} 

này gửi lại một đếm được của mỗi mục mà thất bại và nó tương ứng ngoại lệ.

0

Nếu khối try-catch SomeMethod đã thực hiện của bạn sau đó sẽ tiếp tục foreach

void SomeMethod() 
{ 
    try 
    { 
    //Some operation on i 
    } 
    catch(Exception ex) 
    { 
    } 
} 

Nhưng nếu không sau đó foreach sẽ phá vỡ.

Một cái gì để làm việc đó là cách

list.ForEach(i => 
    { 
     try 
     { 
      i.SomeMethod(); 
     } 
     catch(Exception ex) 
     { 
     } 
    }); 

này Nhưng nó luôn luôn tốt để có zero khối try-catch trong mã của bạn. Khác bạn sẽ không bao giờ tìm thấy nơi thủ phạm là.

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