2010-10-28 12 views
7

Ho una classe con un'API che mi consente di chiedere oggetti finché non getta un IndexOutOfBoundsException.iteratore .NET per avvolgere l'API di lancio

Voglio inserirlo in un iteratore, per poter scrivere codice più pulito. Tuttavia, ho bisogno di catturare l'eccezione di fermare l'iterazione:

static IEnumerable<object> Iterator(ExAPI api) { 
    try { 
     for(int i = 0; true; ++i) { 
      yield return api[i]; // will throw eventually 
     } 
    } 
    catch(IndexOutOfBoundsException) { 
     // expected: end of iteration. 
    } 
} 

Ma ...

Quando viene utilizzato con l'espressione, una dichiarazione dei rendimenti non può apparire in un blocco cattura o in una prova blocco che ha una o più clausole di cattura. Per ulteriori informazioni su , consultare Gestione delle eccezioni. Dichiarazioni (riferimento C#) .Statements (riferimento C#). (dal msdn)

Come posso ancora avvolgere questa API?

+0

@Coding Gorilla: questo è il punto: no. Inizia da zero e sale. – xtofl

risposta

14

è sufficiente spostare l'istruzione yield return al di fuori del blocco try, in questo modo:

static IEnumerable<object> Iterator(ExAPI api) { 
    for(int i = 0; true; ++i) { 
     object current; 
     try { 
      current = api[i]; 
     } catch(IndexOutOfBoundsException) { yield break; } 

     yield return current; 
    } 
} 
+0

sebbene non sia necessario un "se (corrente! = Null) restituisce la corrente"? –

+0

oh aspetta im dumb ho perso la pausa di rendimento. –

+0

La documentazione dell'istruzione 'yield break' è stata lasciata su msdn ... Grazie per aver segnalato! – xtofl

0

Proprio riordinare il codice:

static IEnumerable<object> Iterator(ExAPI api) { 
    bool exceptionThrown = false; 
    object obj = null; 
    for(int i = 0; true; ++i) { 
     try { 
      obj = api[i]; 
     } 
     catch(IndexOutOfBoundsException) { 
      exceptionThrown = true; 
      yield break; 
     } 

     if (!exceptionThrown) { 
      yield return obj; 
     } 
    } 
} 
+0

Questo non si fermerà mai. – SLaks

+0

No, ho scritto troppo velocemente, credo .... Comunque, la tua risposta qui sotto è più pulita e migliore :-) – AHM

+0

Ora hai una variabile inutile. – SLaks

4

si può avvolgere la semplice operazione di ottenere l'oggetto in una funzione separata. È possibile intercettare l'eccezione in là:

bool TryGetObject(ExAPI api, int idx, out object obj) 
{ 
    try 
    { 
     obj = api[idx]; 
     return true; 
    } 
    catch(IndexOutOfBoundsException) 
    { 
     return false; 
    }   
} 

Quindi, chiamare tale funzione e terminare se necessario:

static IEnumerable<object> Iterator(ExAPI api) 
{ 
    bool abort = false; 

    for(int i = 0; !abort; ++i) 
    { 
     object obj; 
     if(TryGetObject(api, i, out obj)) 
     { 
      yield return obj; 
     } 
     else 
     { 
      abort = true; 
     } 
    } 
} 
+0

Non sono davvero un fan di questo approccio. Se l'API è accessibile solo in questo metodo, un metodo separato per ottenere l'oggetto è un po 'ridondante. –

+0

@Joshua: ma una lambda potrebbe funzionare ... – xtofl

0

Se non è possibile controllare i limiti dell'oggetto a tutti, si potrebbe fare qualcosa così

sebbene ora che sto guardando qui, la risposta sopra è meglio credo. Quello pubblicato da SLaks.

+0

Infatti: la mia intenzione è non riempire un contenitore, ma piuttosto fornire un iteratore. – xtofl

0
static IEnumerable<object> Iterator(ExAPI api) 
    { 
     int i = 0; 
     while (true) 
     { 
      Object a; 
      try 
      { 
       a = api[i++]; 
      } 
      catch (IndexOutOfBoundsException) 
      { 
       yield break; 
      } 
      yield return a; 
     } 
    }