2011-01-01 45 views
17

Tôi làm cách nào để khởi động lại vòng lặp foreach trong C# ??Khởi động lại vòng lặp foreach trong C#?

Ví dụ:

Action a; 
foreach(Constrain c in Constrains) 
{ 
    if(!c.Allows(a)) 
    { 
     a.Change(); 
     restart; 
    } 
} 

restart ở đây là như continue hoặc break nhưng nó khởi động lại foreach từ đầu Nó giống như thiết lập các truy cập của một for vòng lặp để 0 một lần nữa ..

Is có thể trong C#?

Edit: Tôi muốn cảm ơn tất cả Mehrdad Afshari và Mahesh Velaga đã cho tôi phát hiện ra một lỗi (index = 0) trong việc thực hiện hiện tại của tôi, rằng sẽ không có được phát hiện bằng cách khác ..

+0

Có thể thú vị khi biết chính xác nơi bạn cần sử dụng kiểu khởi động lại này. Bạn đang sử dụng danh sách các đối tượng có thể thay đổi trong một số loại thuật toán. Bạn có thể chia sẻ vấn đề thực tế mà bạn đang cố gắng giải quyết không? –

+0

Vấn đề thực tế: một số tác nhân cố gắng di chuyển trong môi trường. Có những rào cản trong env. Sau mỗi tác nhân quyết định hành động chuyển động tiếp theo là gì, môi trường sẽ kiểm tra xem nhân viên có vượt qua rào cản hay không, nếu có, môi trường cho phép tác nhân chọn một hành động khác; và ở đây, nơi tôi cần phải khởi động lại vòng lặp foreach để kiểm tra tất cả các rào cản một lần nữa với hành động mới được chọn .. Tôi hy vọng rằng làm cho rõ ràng ... – Betamoo

Trả lời

53

Sử dụng tốt cũ goto :

restart: 
foreach(Constrain c in Constrains) 
{ 
    if(!c.Allows(a)) 
    { 
     a.Change(); 
     goto restart; 
    } 
} 

Nếu bạn được chẩn đoán với gotophobia 100% thời gian đối với một số lý do (mà là không một điều tốt mà không có một lý do nào), bạn có thể thử sử dụng một lá cờ thay vì:

bool restart; 
do { 
    restart = false; 
    foreach(Constrain c in Constrains) 
    { 
     if(!c.Allows(a)) 
     { 
     a.Change(); 
     restart = true; 
     break; 
     } 
    } 
} while (restart); 
+3

+1 Tôi thích việc thực hiện vòng lặp của bạn. –

+8

Hãy cẩn thận với gotos http://xkcd.com/292/ – digEmAll

+1

hãy cẩn thận! trong dotnet3.5 và hơn thế nữa (LINQ, v.v.), foreach() có thể bị đóng. Giải pháp này, hoặc bất kỳ giải pháp nào khác nhảy ra khỏi vòng lặp, sẽ loại bỏ việc đóng cửa một cách chính xác. Nhưng hãy nghĩ về nó; đây là loại nơi mà thiết kế cẩn thận sẽ tiết kiệm rất nhiều gỡ lỗi. –

4
void Main() 
{ 
    IEnumerable<Constrain> cons; 
    SomeObject a; 

    while(!TryChangeList(cons, a)) { } 
} 

// the name tryChangeList reveals the intent that the list will be changed 
private bool TryChangeList(IEnumerable<Constrain> constrains, SomeObject a) 
{ 
    foreach(var con in constrains) 
    { 
     if(!c.Allows(a)) 
     { 
      a.Change(); 
      return false; 
     } 
    } 
    return true; 
} 
+0

+1. Tái cấu trúc thường là một giải pháp tốt trong loại trường hợp này nếu nó khả thi và không làm cho mọi thứ trở nên phức tạp hơn. –

+1

-1 nếu nó không phải là 'IList 'thì sao? –

+0

@ John - nó cũng sẽ hoạt động cho IEnumerable nếu bạn thay đổi IList thành IEnumerable –

8

Một cách để bạn có thể làm điều đó được sử dụng cho, như bạn đã đề cập:

khởi động lại ở đây cũng giống như tiếp tục hoặc phá vỡ nhưng nó khởi động lại foreach từ khởi điểm Đó là như thiết lập bộ đếm của vòng lặp for 0 một lần nữa

Action a; 
for(var index = 0; index < Constratins.Count; index++) 
{ 
    if(!Constraints[index].Allows(a)) 
    { 
     a.Change(); 
     index = -1; // restart 
    } 
} 
+7

Điều này là sai. 'index = -1' sẽ hoạt động, nếu enumerable là index-accessible nhưng ngay cả trong trường hợp đó, nó làm cho mã khó đọc và làm cho ý định không rõ ràng. Đây là một ví dụ hoàn hảo của việc làm những điều tồi tệ hơn như là kết quả của chứng sợ hãi mù. Ít nhất, với 'goto', mục đích là hoàn toàn rõ ràng. –

+0

+1 Đây là giải pháp đầu tiên xuất hiện trong đầu - Tại sao không sử dụng vòng lặp for? Tại sao tạo ra một giải pháp foreach bừa bãi. –

+0

@Mehrdad: sửa phần chỉ mục. Cảm ơn –

0
for (var en = Constrains.GetEnumerator(); en.MoveNext();) 
{ 
    var c = en.Current; 
    if (!c.Allows(a)) 
    { 
     a.Change(); 
     en = Constrains.GetEnumerator(); 
    } 
} 
+4

Bạn sẽ muốn Vứt bỏ bản gốc trước. –

+3

@John: Thật vậy. Và bạn phải đối phó với các ngoại lệ tiềm năng, ... mà cuối cùng dẫn đến một câu lệnh 'sử dụng', và vào thời điểm đó, bạn sẽ nhận ra rằng bạn không nên bỏ rơi 'foreach' ngay từ đầu! –

8

Mặc dù một sợi rất cũ - không ai trong số các câu trả lời quan tâm đúng mức đến ngữ nghĩa của mã mà:

  • Bạn có một chuỗi các khó khăn về a
  • Nếu a phá vỡ bất kỳ trong số họ, hãy thử a khác và đẩy nó qua chuỗi.

Đó là, a.Change() nên được tách ra từ kiểm tra hạn chế vòng lặp, cũng tôn trọng những nguyên tắc CQS:

while (!MeetsConstraints(a)) 
{ 
    a.Change(); 
} 

bool MeetsConstraints(Thing a) 
{ 
    return Constraints.All(c => c.Allows(a)); 
} 

Không goto, không có vòng xấu xí, chỉ cần đơn giản và sạch sẽ. </self-back-slapping >

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