for examples ejemplo array c# foreach ienumerable ienumerator

c# - examples - ¿Puedo tener un método que devuelva IEnumerator<T> y usarlo en un bucle foreach?



list c# (5)

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

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:

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

Utilizándolo así:

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

Pero, por supuesto, el compilador escupe su variable 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 () ?


Si devuelve IEnumerator, será un objeto enumerador diferente cada vez que llame a ese método (actuando como si restableciera 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.


Si recibe un enumerador y necesita usarlo en un bucle for-each, puede usar lo siguiente para ajustarlo:

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 c # o vb considere un tipo de devolución aceptable de GetEnumerator y devolverá algo que se pueda utilizar en foreach . Si el parámetro es un IEnumerator<> la respuesta será un IEnumerable<T> , aunque llamar a GetEnumerator una vez probablemente dará malos resultados.


Solo para aclarar

private static IEnumerator<TextBox> FindTextBoxes(Control rootControl)

Cambios a

private static IEnumerable<TextBox> FindTextBoxes(Control rootControl)

Eso debería ser todo :-)


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