2010-10-28 14 views
7

Tengo una clase con una API que me permite solicitar objetos hasta que arroja un IndexOutOfBoundsException.iterador .NET para envolver throwing API

Quiero envolverlo en un iterador, para poder escribir código limpiador. Sin embargo, tengo que coger la excepción para detener la iteración:

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

Pero ...

Cuando se utiliza con la expresión, una instrucción de retorno rendimiento no puede aparecer en un bloque captura o en un intento bloque que tiene una o más cláusulas catch. Para obtener más información acerca de , consulte Manejo de excepciones Declaraciones (Referencia de C#). Declaraciones (Referencia de C#). (del msdn)

¿Cómo puedo todavía envolver esta API?

+0

@Coding Gorilla: ese es el punto: no. Comienza desde cero y sube. – xtofl

Respuesta

14

sólo hay que mover la declaración yield return exterior del bloque try, así:

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

aunque no necesitaría un "if (current! = Null) return current"? –

+0

oh wait im tonto me perdí el salto de producción. –

+0

La documentación de la declaración 'yield break' se deja en el msdn ... ¡Gracias por señalar! – xtofl

0

Sólo reordenar el código:

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

Esto nunca se detendrá. – SLaks

+0

No, escribí demasiado rápido, supongo ... De todos modos, tu respuesta a continuación es más clara y mejor :-) – AHM

+0

Ahora tienes una variable inútil. – SLaks

4

se puede envolver la operación sencilla de conseguir el objeto en una función separada. Se puede detectar la excepción allí:

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

A continuación, llamar a esa función y terminar si es necesario:

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

No soy realmente un fan de este enfoque. Si solo se accederá a la API en este método, un método diferente para obtener el objeto es algo redundante. –

+0

@Joshua: pero una lambda podría funcionar ... – xtofl

0

Si no puede comprobar los límites del objeto en absoluto, se podría hacer algo como este

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

aunque ahora que estoy buscando aquí, la respuesta anterior es mejor, creo. El único SLaks publicado.

+0

De hecho, mi intención es no llenar un contenedor, sino proporcionar un iterador. – 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; 
     } 
    }