2012-09-21 17 views
8

Ho un ciclo foreach che si interrompe durante il ciclo nella condizione del foreach stesso. C'è un modo per try catch l'elemento che genera l'eccezione e quindi continua il ciclo?Eccezione di cattura lanciata in condizione foreach

Questo verrà eseguito alcune volte fino a quando l'eccezione non colpisce e quindi termina.

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

Questo non funzionerà affatto perché l'eccezione è nella condizione del foreach

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

So che alcuni di voi stanno per chiedere come questo sta accadendo: ecco questo: Eccezione PrincipalOperationException viene generato perché non è possibile trovare Principal (b nel mio esempio) in GroupPrincipal (api).

Modifica: Ho aggiunto il codice qui sotto. Ho anche capito che un membro del gruppo stava indicando un dominio che non esiste più. Ho risolto facilmente questo problema eliminando il membro, ma la mia domanda rimane valida. Come gestisci le eccezioni che vengono lanciate nella condizione di un 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

Il problema non è in una "condizione". È in procinto di enumerare l'oggetto 'api '. Per scopi di debug, prova a "manualmente" enumerare "api". È una sorta di 'IEnumerable ' o 'IEnumerable'. Fai manualmente '.MoveFirst()' e vedi se ottieni subito l'eccezione. –

+0

Wow, non avevo realizzato che il C# non avesse un curriculum al prossimo ... Ho appena trovato tutti questi forum di ragazzi che cercano l'equivalente. Suppongo che sia solo un altro aspetto positivo dell'essere uno sviluppatore di VB.net. Le mie scuse coniugano – Ccorock

+0

@mellamokb, in realtà non lo uso troppo io stesso. Lavoravo con un programmatore C++ piuttosto interessante che era stato costretto a scrivere in Vb.net, avrebbe sparpagliato il maledetto codice con On error resume next. Perché dovrei fare qualcosa qui? – Ccorock

risposta

3

Quasi la stessa come la risposta da @Guillaume, ma "Mi piace il mio meglio":

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

mi piace il mio meglio anche ... Comunque ha più senso di gettare eccezione che l'esecuzione del 'Action' se non c'è l'enumerazione. Qual è la ragione per eseguire prima il comando "MoveNext" anziché eseguirlo nel ciclo? – Guillaume

+0

@Guillaume: non un grande affare, ma in questo modo non c'è ritorno dalla metà del ciclo. È un problema di stile minore e un po 'meno da pensare. –

3

Forse si può provare a creare un metodo del genere:

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); 
    } 

e si può usare in questo modo:

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

non ben programmato: list.Count(); enumera la lista completa già, e il ciclo for è anche il modo sbagliato per enumerare un'enumerazione – user287107

+0

Credo che non funziona, perché list.Count() genera già il messaggio di errore – user287107

+3

Inoltre, perché dovrebbe enumerator.MoveNext(); restituire un buon valore dopo aver generato un'eccezione? – user287107

0

Preferisco utilizzare un gestore di eccezioni aggregato. non c'è bisogno di estensioni.

NET Framework 4.6 e 4,5

AggregateException Class non hanno testato il codice, ma la logica è lì.

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); 
     }); 
    } 
Problemi correlati