c# - Puis-je avoir une méthode renvoyant IEnumerator <T> et l'utiliser dans une boucle foreach?

Translate

Je dois définir la hauteur de chaque zone de texte sur mon formulaire, dont certaines sont imbriquées dans d'autres contrôles. J'ai pensé que je pouvais faire quelque chose comme ça:

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

En l'utilisant comme ceci:

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

Mais bien sûr, le compilateur crache son mannequin, carpour chaqueattend unIEnumerableplutôt qu'unIEnumérateur.

Y a-t-il un moyen de faire cela sans avoir à créer une classe séparée avec unGetEnumerator ()méthode?

This question and all comments follow the "Attribution Required."

Toutes les réponses

Translate

Comme le compilateur vous le dit, vous devez changer votre type de retour en IEnumerable. C'est ainsi que fonctionne la syntaxe de retour de rendement.

La source
Translate

Juste pour clarifier

private static IEnumerator<TextBox> FindTextBoxes(Control rootControl)

Modifications de

private static IEnumerable<TextBox> FindTextBoxes(Control rootControl)

Cela devrait être tout :-)

La source
Translate

Si vous retournez IEnumerator, ce sera un objet énumérateur différent chaque fois que vous appelez cette méthode (agissant comme si vous réinitialisez l'énumérateur à chaque itération). Si vous retournez IEnumerable, un foreach peut énumérer en fonction de la méthode avec l'instruction yield.

La source
Translate
// 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;
    }
}
La source
Translate

Si vous disposez d'un énumérateur et que vous devez l'utiliser dans une boucle for-each, vous pouvez utiliser ce qui suit pour l'envelopper:

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

letoEnumerableméthode acceptera tout ce quiouconsidérerait un type de retour acceptable deGetEnumerator, et renvoyez quelque chose qui peut être utilisé dansforeach. Si le paramètre est unIEnumerator<>la réponse sera unIEnumerable<T>, en appelantGetEnumeratordessus une fois donnera probablement de mauvais résultats.

La source