2008-08-06 21 views
15

Necesito establecer el alto de cada cuadro de texto en mi formulario, algunos de los cuales están anidados dentro de otros controles. Pensé que podría hacer algo como esto:¿Puedo tener un método que devuelva IEnumerator <T> y usarlo en un bucle foreach?

private static IEnumerator<TextBox> FindTextBoxes(Control rootControl) 
{ 
    foreach (Control control in rootControl.Controls) 
    { 
     if (control.Controls.Count > 0) 
     { 
      // Recursively search for any TextBoxes within each child control 
      foreach (TextBox textBox in FindTextBoxes(control)) 
      { 
       yield return textBox; 
      } 
     } 

     TextBox textBox2 = control as TextBox; 
     if (textBox2 != null) 
     { 
      yield return textBox2; 
     } 
    } 
} 

Usando esta manera:

foreach(TextBox textBox in FindTextBoxes(this)) 
{ 
    textBox.Height = height; 
} 

Pero, por supuesto, el compilador escupe su ficticia, porque foreach espera un IEnumerable en lugar de un IEnumerator.

¿Hay alguna manera de hacerlo sin tener que crear una clase separada con un método GetEnumerator()?

+2

En realidad, 'foreach' no espera un' IEnumerable' en absoluto (ni un 'IEnumerable '). Solo espera algo que tenga un método 'GetEnumerator'. Ese método, a su vez, no necesariamente debe devolver un 'IEnumerator' o' IEnumerator '- solo necesita devolver algo que tenga un método' MoveNext() 'y una propiedad' Current'. – Timwi

Respuesta

13

Como el compilador le dice, debe cambiar su tipo de devolución a IEnumerable. Así es como funciona la sintaxis de retorno de rendimiento.

+6

'yield return' se puede usar con métodos que devuelven * cualquiera *' IEnumerable '* o *' IEnumerator '. Está solo en el bucle 'foreach' donde' IEnumerator 'no se puede usar. – Timwi

1
// Generic function that gets all child controls of a certain type, 
// returned in a List collection 
private static List<T> GetChildTextBoxes<T>(Control ctrl) where T : Control{ 
    List<T> tbs = new List<T>(); 
    foreach (Control c in ctrl.Controls) { 
     // If c is of type T, add it to the collection 
     if (c is T) { 
      tbs.Add((T)c); 
     } 
    } 
    return tbs; 
} 

private static void SetChildTextBoxesHeight(Control ctrl, int height) { 
    foreach (TextBox t in GetChildTextBoxes<TextBox>(ctrl)) { 
     t.Height = height; 
    } 
} 
3

Si regresa IEnumerator, será un objeto enumerador diferente cada vez que llame a ese método (que actúa como si se restablece el enumerador en cada iteración). Si devuelve IEnumerable, un foreach puede enumerar en función del método con la declaración de rendimiento.

9

sólo para aclarar

private static IEnumerator<TextBox> FindTextBoxes(Control rootControl) 

Cambios en

private static IEnumerable<TextBox> FindTextBoxes(Control rootControl) 

eso se debe todo :-)

0

Si se le da un enumerador, y hay que usarla en un para- cada ciclo, puede usar lo siguiente para envolverlo:

 
static public class enumerationHelper 
{ 
    public class enumeratorHolder<T> 
    { 
     private T theEnumerator; 
     public T GetEnumerator() { return theEnumerator; } 
     public enumeratorHolder(T newEnumerator) { theEnumerator = newEnumerator;} 
    } 
    static enumeratorHolder<T> toEnumerable<T>(T theEnumerator) { return new enumeratorHolder<T>(theEnumerator); } 
    private class IEnumeratorHolder<T>:IEnumerable<T> 
    { 
     private IEnumerator<T> theEnumerator; 
     public IEnumerator<T> GetEnumerator() { return theEnumerator; } 
     System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator() { return theEnumerator; } 
     public IEnumeratorHolder(IEnumerator<T> newEnumerator) { theEnumerator = newEnumerator; } 
    } 
    static IEnumerable<T> toEnumerable<T>(IEnumerator<T> theEnumerator) { return new IEnumeratorHolder<T>(theEnumerator); } 
} 

El método toEnumerable aceptará cualquier cosa que o considere un tipo de devolución aceptable de GetEnumerator, y devuelva algo que se puede usar en foreach. Si el parámetro es IEnumerator<>, la respuesta será IEnumerable<T>, aunque llamar al GetEnumerator una vez probablemente arroje malos resultados.

Cuestiones relacionadas