2009-02-17 57 views
30

在正常的循環中,您可以使用break來打破循環。這同樣可以使用匿名委託來完成嗎?如何在使用匿名代理時退出列表<string> .ForEach循環?

示例 inputString和result都在委託之外聲明。

blackList.ForEach(new Action<string>(
    delegate(string item) 
    { 
     if(inputString.Contains(item)==true) 
     { 
      result = true; 
      // I want to break here 
     } 
    } 
)); 

編輯: 感謝您的答覆,我其實是讀你的書在一分鐘約翰:)只是爲了記錄我打這個問題和切換回正常foreach循環,但我張貼了這個問題看看我是否錯過了什麼。

+0

[List ForEach break]可能的重複(http://stackoverflow.com/questions/3145563/list-foreach-break) – 2014-03-24 14:40:50

回答

31

正如其他人發佈的那樣,您無法在ForEach中退出循環。

你能夠使用LINQ嗎?如果是這樣,您可以輕鬆地將TakeWhile和自定義的ForEach擴展方法(幾乎每個項目似乎都有這些天)結合起來。

在你的榜樣,但是,List<T>.FindIndex將是最好的選擇 - 但如果你沒有真正這樣做,請發表你真的想做的事情的例子。

2

「退出」循環的唯一方法是拋出異常。沒有「break」風格的方式退出.ForEach方法,就像正常的foreach循環一樣。

6

我不認爲使用ForEach方法時有一種優雅的方式可以做到這一點。哈克解決方案是拋出一個異常。

什麼阻止你做一個老式的foreach?

foreach (string item in blackList) 
{ 
    if (!inputString.Contains(item)) continue; 

    result = true; 
    break; 
} 
+1

絕對沒有,我只是想了解更多關於代表和他們的限制。 – SecretDeveloper 2009-02-17 15:17:44

+0

長五行! + 500%! – 2016-03-11 12:05:51

3

如果你想要一個循環,使用循環。

Action允許沒有返回值,所以ForEach函數不可能知道你想中斷,拋出異常。在這裏使用異常是矯枉過正。

2

ForEach方法並不意味着要做到這一點。如果你想知道一個集合是否包含一個項目,你應該使用Contains方法。如果您想對集合中的所有項目執行檢查,則應嘗試使用Any擴展方法。

23

有沒有循環,有權訪問,從中斷。每個對(匿名)委託的調用都是一個新的函數調用,所以局部變量不會有幫助。但由於C#爲您提供了一個關閉,你可以設置一個標誌,然後什麼也不做進一步的電話:(這需要進行測試,以檢查是否產生了用於關閉正確引用語義)

bool stop = false; 
myList.ForEach((a) => { 
    if (stop) { 
    return; 
    } else if (a.SomeCondition()) { 
    stop = true; 
    } 
}); 

更先進的方法是創建一個允許委託返回false就停止循環自己的擴展方法:

static class MyExtensions { 
    static void ForEachStoppable<T>(this IEnumerable<T> input, Func<T, bool> action) { 
    foreach (T t in input) { 
     if (!action(t)) { 
     break; 
     } 
    } 
    } 
} 
14

你有LINQ提供給你?你的邏輯似乎類似於任何:

bool any = blackList.Any(s=>inputString.Contains(s)); 

這是一樣的:

bool any = blackList.Any(inputString.Contains); 

如果你沒有LINQ,那麼這仍然是一樣的:

bool any = blackList.Find(inputString.Contains) != null; 

如果你想運行額外的邏輯,你可以做的事情(用LINQ)TakeWhile

1
class Program 
{ 
    static void Main(string[] args) 
    { 
     List<string> blackList = new List<string>(new[] { "jaime", "jhon", "febres", "velez" }); 
     string inputString = "febres"; 
     bool result = false; 
     blackList.ForEach((item) => 
           { 
            Console.WriteLine("Executing"); 
            if (inputString.Contains(item)) 
            { 
             result = true; 
             Console.WriteLine("Founded!"); 
            } 
           }, 
         () => result); 
     Console.WriteLine(result); 
     Console.ReadLine(); 
    } 


} 
public static class MyExtensions 
{ 
    public static void ForEach<T>(this IEnumerable<T> enumerable, Action<T> action, Func<bool> breakOn) 
    { 
     foreach (var item in enumerable) 
     { 
      action(item); 
      if (breakOn()) 
      { 
       break; 
      } 
     } 
    } 
} 
1
bool @break = false; 

blackList.ForEach(item => 
{ 
    if([email protected] && inputString.Contains(item)) 
    { @break = true; 
     result = true; 
    } 

    if (@break) return; 
    /* ... */ 
}); 

請注意,上述仍然會遍歷每個項目,但立即返回。當然,這種方式可能不如正常的foreach

0

將這工作給你:

bool result = null != blackList.Find(item => inputString.Contains(item))); 
1

如果你真的想在列表中存在一個循環的foreach你可以使用這樣的代碼例外:

public class ExitMyForEachListException : Exception 
{ 
    public ExitMyForEachListException(string message) 
     : base(message) 
    { 
    } 
} 
class Program 
{ 
    static void Main(string[] args) 
    { 
     List<string> str = new List<string>() { "Name1", "name2", "name3", "name4", "name5", "name6", "name7" }; 
     try 
     { 
      str.ForEach(z => 
      { 
       if (z.EndsWith("6")) 
        throw new ExitMyForEachListException("I get Out because I found name number 6!"); 
       System.Console.WriteLine(z); 
      }); 
     } 
     catch (ExitMyForEachListException ex) 
     { 
      System.Console.WriteLine(ex.Message); 
     } 

     System.Console.Read(); 
    } 
} 

希望這有助於獲得其他觀點。