2012-09-21 8 views
8

Mam pętlę foreach, która zrywa się podczas pętli w stanie samego forea. Czy istnieje sposób na zgłoszenie wyjątku, a następnie kontynuowanie pętli?Wyjątek połowu zgłoszony w warunku foreach

Uruchomi to kilka razy, aż wyjątek trafi, a następnie zakończy.

try { 
    foreach(b in bees) { //exception is in this line 
    string += b; 
    } 
} catch { 
    //error 
} 

To nie będzie działać w ogóle ponieważ wyjątek jest w kondycji foreach

foreach(b in bees) { //exception is in this line 
    try { 
     string += b; 
    } catch { 
    //error 
    } 
} 

Wiem, że niektórzy z was zapytać, jak to się dzieje, więc tutaj jest to: Wyjątek PrincipalOperationException jest wyrzucane, ponieważ Principal (b w moim przykładzie) nie można znaleźć w GroupPrincipal (pszczoły).

Edytuj: Dodałem poniższy kod. Zorientowałem się również, że jeden z członków grupy wskazuje na domenę, która już nie istnieje. Z łatwością naprawiłem to, usuwając członka, ale moje pytanie wciąż jest aktualne. Jak radzisz sobie z wyjątkami, które są wyrzucane w warunkach foreach?

PrincipalContext ctx = new PrincipalContext(ContextType.domain); 
GroupPrincipal gp1 = GroupPrincipal.FindByIdentity(ctx, "gp1"); 
GroupPrincipal gp2 = GroupPrincipal.FindByIdentity(ctx, "gp2"); 

var principals = gp1.Members.Union(gp2.Members); 

foreach(Principal principal in principals) { //error is here 
    //do stuff 
} 
+3

Problem nie jest w "stanie". Jest w trakcie wyliczania obiektu "pszczoły". W celu debugowania spróbuj "ręcznie" wyliczyć "pszczoły". Jest to rodzaj 'IEnumerable ' lub 'IEnumerable'. Ręcznie wykonaj '.MoveFirst()' i sprawdź, czy od razu otrzymasz wyjątek. –

+0

Wow, nie zdawałem sobie sprawy, że C# nie ma żadnego życiorysu w następnej ... Właśnie znalazłem wszystkie fora facetów szukających odpowiednika. Przypuszczam, że jest to kolejna dobra rzecz o byciu deweloperem VB.net. Moje przeprosiny kojarzą się z – Ccorock

+0

@mellamokb, Właściwie nie używam go zbyt wiele sam. Pracowałem z dość interesującym programistą C++, który był zmuszony napisać w Vb.net, chciał zaśmiecić ten cholerny kod za pomocą opcji On error resume next. Po co mam tu coś zrobić? – Ccorock

Odpowiedz

3

prawie taka sama jak odpowiedź od @Guillaume, ale "Lubię moje lepiej":

public static class Extensions 
{ 
    public static IEnumerable<T> TryForEach<T>(this IEnumerable<T> sequence, Action<Exception> handler) 
    { 
     if (sequence == null) 
     { 
      throw new ArgumentNullException("sequence"); 
     } 

     if (handler == null) 
     { 
      throw new ArgumentNullException("handler"); 
     } 

     var mover = sequence.GetEnumerator(); 
     bool more; 
     try 
     { 
      more = mover.MoveNext(); 
     } 
     catch (Exception e) 
     { 
      handler(e); 
      yield break; 
     } 

     while (more) 
     { 
      yield return mover.Current; 
      try 
      { 
       more = mover.MoveNext(); 
      } 
      catch (Exception e) 
      { 
       handler(e); 
       yield break; 
      } 
     } 
    } 
} 
+0

Ja też lubię lepiej ... Jednak bardziej sensowne jest rzucanie wyjątku niż wykonywanie "Akcji", jeśli nie ma wyliczenia. Jaki jest powód pierwszego wykonywania 'MoveNext' zamiast po prostu robić to w pętli? – Guillaume

+0

@Guillaume: nic wielkiego, ale w ten sposób nie ma powrotu z połowy pętli. To drobny problem z stylem i trochę mniej, o czym trzeba pomyśleć. –

3

Być może można spróbować stworzyć metodę tak:

public IEnumerable<T> TryForEach<T>(IEnumerable<T> list, Action executeCatch) 
    { 
     if (list == null) { executeCatch(); } 
     IEnumerator<T> enumerator = list.GetEnumerator(); 
     bool success = false; 

     do 
     { 
      try 
      { 
       success = enumerator.MoveNext(); 
      } 
      catch 
      { 
       executeCatch(); 
       success = false; 
      } 

      if (success) 
      { 
       T item = enumerator.Current; 
       yield return item; 
      } 
     } while (success); 
    } 

i można go używać w ten sposób:

 foreach (var bee in TryForEach(bees.GetMembers(),() => { Console.WriteLine("Error!"); })) 
     { 
     } 
+0

źle zaprogramowany: list.Count(); wylicza już pełną listę, a pętla for jest również niewłaściwym sposobem wyliczenia wyliczenia – user287107

+0

Domyślam się, że to nie działa, ponieważ list.Count() już rzuca komunikat o błędzie – user287107

+3

dodatkowo, dlaczego powinien być enumerator.MoveNext(); zwrócić dobrą wartość po rzuceniu wyjątku? – user287107

0

Wolę używać agregującej obsługi wyjątków. nie ma potrzeby rozszerzenia.

.NET Framework 4.6 i 4,5

AggregateException Class nie testowałem ten kod, ale logika jest tam.

try 
    { 
     foreach (var item in items) 
     { 
      try 
      { 
       //something 
       //your own exception (eg.) 
       if (item < 0x3) 
        throw new ArgumentException(String.Format("value is {0:x}. Elements must be greater than 0x3.")); 
      } 
      catch (Exception regularException) 
      { 
       //predefined exceptions (eg.) 
       throw new ArgumentException(regularException.InnerException.ToString()); 
      } 
     } 
    } 
    catch (AggregateException ae) 
    { 
     ae.Handle((inner) => 
     { 
      //handle your aggregate exceptions 
      Debug.WriteLine(inner.Message); 
     }); 
    } 
Powiązane problemy