2010-06-29 32 views
15

có cách nào để thoát ra khỏi phương pháp mở rộng foreach không? Từ khóa "ngắt" không nhận ra phương thức tiện ích mở rộng là phạm vi hợp lệ để thoát khỏi.Danh sách ForEach break

//Doesn't compile 
Enumerable.Range(0, 10).ToList().ForEach(i => { System.Windows.MessageBox.Show(i.ToString()); if (i > 2)break; }); 

Edit: gỡ bỏ "LINQ" từ câu hỏi


lưu ý mã chỉ là một ví dụ cho thấy nghỉ không làm việc trong các phương pháp khuyến nông ... thực sự những gì tôi muốn là cho người dùng có thể hủy bỏ việc xử lý danh sách .. chuỗi giao diện người dùng có biến số hủy và vòng lặp for chỉ bị ngắt khi người dùng nhấn nút hủy. Ngay bây giờ, tôi có một vòng lặp bình thường, nhưng tôi muốn xem nếu nó có thể làm với phương pháp mở rộng.

Trả lời

16

Có thể chính xác hơn khi gọi đây là List<T> Foreach so với LINQ.

Trong cả hai trường hợp, mặc dù không có cách nào để thoát khỏi vòng lặp này. Chủ yếu là vì nó không thực sự là một vòng lặp cho mỗi nói. Đó là một phương pháp mà có một đại biểu được gọi là bên trong một vòng lặp.

Tạo một ForEach với khả năng phá vỡ được khá thẳng về phía trước mặc dù

public delegate void ForEachAction<T>(T value, ref bool doBreak); 
public static void ForEach<T>(this IEnumerable<T> enumerable, ForEachAction<T> action) { 
    var doBreak = false; 
    foreach (var cur in enumerable) { 
     action(cur, ref doBreak); 
     if (doBreak) { 
      break; 
     } 
    } 
} 

Sau đó bạn có thể viết lại mã của bạn như sau

Enumerable.Range(0,10) 
    .ForEach((int i,ref bool doBreak) => { 
     System.Windows.MessageBox.Show(i.ToString()); 
     if (i > 2) {doBreak = true;} 
    }); 
3

Tại sao không sử dụng Where?

Enumerable.Range(0, 10).Where(i => i <= 2).ToList().ForEach(...) 
11

Tôi khuyên bạn nên sử dụng TakeWhile.

Enumerable.Range(0, 10).TakeWhile(i => i <= 2).ToList().ForEach(i => MessageBox.Show(i.ToString())); 

Hoặc, sử dụng Rx:

Enumerable.Range(0, 10).TakeWhile(i => i <= 2).Run(i => MessageBox.Show(i.ToString())); 
0

Tại sao không sử dụng foreach? ...

PS: Chỉ đùa thôi, như bạn đã đề cập, tôi hiểu ý tưởng cố gắng xem làm thế nào để làm điều đó với LINQ (và googled ở đây vì lý do tương tự) ... bây giờ vì lý do bảo trì/sẵn sàng trong sản xuất mã đoán một đơn giản foreach là đủ tốt đôi khi.

1

Hãy thử câu lệnh "return" thay vì "break"; đó là một chức năng đại biểu và không phải là một vòng lặp thực sự.

Hãy thử:

Enumerable.Range(0, 10).ToList().ForEach(i => { System.Windows.MessageBox.Show(i.ToString()); if (i > 2) return; }); 
0

Đối với bản thân mình, tôi đã sử dụng LINQ Chọn + FirstOrDefault. Chuyển đổi "mỗi" trong danh sách nhưng vì chúng ta đang yêu cầu Đầu tiên, nó sẽ ngừng chuyển đổi chúng sau khi tìm thấy cái đầu tiên khớp với nhau.

var thingOption = list.Select(thing => AsThingOption(thing)) 
.FirstOrDefault(option => option.HasValue) ?? Option.None<MyThing>; 

Như bạn có thể thấy tôi đang chuyển đổi từng mục thành tùy chọn và phương pháp AsThingOption có thể thành công khi chuyển đổi và khi nào chúng tôi dừng lặp lại trong danh sách. Nếu các điều kiện bên trong phương thức AsThingOption không bao giờ thành công khi chuyển đổi, thì kết quả cuối cùng là None.

Hy vọng điều đó sẽ hữu ích!

0

Tại sao không throw new Exception("Specific message") hoặc sử dụng cờ boolean?

DataTable dt = new DataTable(); 
bool error = false; 

try 
{ 
    dt.AsEnumerable().ToList().ForEach(dr => 
    { 
     if (dr["Col1"].ToString() == "") 
     { 
      error = true; 
      throw new Exception("Specific message"); 
     } 
     else 
      // Do something 
    }); 
} 
catch (Exception ex) 
{ 
    if (ex.Message == "Specific message" || error) 
     // do something 
    else 
     throw ex; 
} 
0

Tôi có một trường hợp mà tôi cần phải hành động lặp cho đến khi một điều kiện là sai và mỗi hành động có thể thay đổi giá trị sử dụng để theo dõi tình trạng này. Tôi đã đưa ra biến thể này của .TakeWhile(). Lợi thế ở đây là mỗi mục trong danh sách có thể tham gia vào một số logic, sau đó vòng lặp có thể bị hủy bỏ trên một điều kiện không liên quan trực tiếp đến mục đó.

new List<Action> { 
    Func1, 
    Func2 
}.TakeWhile(action => { 
    action(); 
    return _canContinue; 
}); 
Các vấn đề liên quan