2010-10-28 6 views
7

J'ai une classe avec une API qui me permet de demander des objets jusqu'à ce qu'il lance un IndexOutOfBoundsException..NET itérateur pour lancer API de lancement

Je veux l'envelopper dans un itérateur, pour pouvoir écrire du code plus propre. Cependant, je dois attraper l'exception pour arrêter itérer:

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. 
    } 
} 

Mais ...

Lorsqu'il est utilisé avec l'expression, une déclaration de retour rendement ne peut pas apparaître dans un bloc catch ou dans un essai bloc qui a une ou plusieurs clauses de capture. Pour plus d'informations sur , voir Gestion des exceptions Instructions (référence C#) .Statements (référence C#). (du msdn)

Comment puis-je envelopper encore cette api?

+0

@Coding Gorilla: c'est le point: non. Cela commence à zéro et remonte. – xtofl

Répondre

14

Il vous suffit de déplacer la déclaration yield return en dehors du bloc try, comme ceci:

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

bien que wouldnt vous besoin d'un courant de retour de rendement de «si (courant! = Null)»? –

+0

oh attends im bête j'ai raté la baisse de rendement. –

+0

La documentation de l'instruction 'yield break' est omise sur msdn ... Merci de m'avoir signalé! – xtofl

0

Juste réordonner le code:

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

Cela ne s'arrêtera jamais. – SLaks

+0

Non, j'ai écrit trop vite je suppose ... De toute façon, votre réponse ci-dessous est plus propre et mieux :-) – AHM

+0

Maintenant, vous avez une variable inutile. – SLaks

4

Vous pouvez envelopper l'opération simple d'obtenir l'objet dans une fonction séparée. Vous pouvez attraper l'exception là:

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

Ensuite, appelez cette fonction et mettre fin si nécessaire:

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

Je ne suis pas vraiment fan de cette approche. Si l'api n'est accessible que dans cette méthode, une méthode séparée pour obtenir l'objet est un peu redondante. –

+0

@Joshua: mais un lambda pourrait fonctionner ... – xtofl

0

Si vous ne pouvez pas vérifier les limites de l'objet du tout, vous pouvez faire quelque chose comme celui-ci

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

bien maintenant que je cherche ici, la réponse ci-dessus vaut mieux je crois. Le seul SLaks posté.

+0

En effet: mon intention est de ne pas remplir un conteneur, mais plutôt de fournir un itérateur. – 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; 
     } 
    }