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

StackOverflow https://stackoverflow.com/questions/3315

Question

Je dois définir la hauteur de chaque zone de texte de mon formulaire, dont certaines sont imbriquées dans d'autres contrôles.Je pensais pouvoir faire quelque chose comme ceci :

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, car pour chaque s'attend à un IEnumerable plutôt qu'un IÉnumérateur.

Existe-t-il un moyen de le faire sans avoir à créer une classe distincte avec un ObtenirEnumérateur() méthode?

Était-ce utile?

La solution

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

Autres conseils

Juste pour clarifier

private static IEnumerator<TextBox> FindTextBoxes(Control rootControl)

Modifications à

private static IEnumerable<TextBox> FindTextBoxes(Control rootControl)

Ce devrait être tout :-)

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

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

Si vous recevez 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); }
}

Le toEnumerable la méthode acceptera tout ce qui ou considérerait un type de retour acceptable de GetEnumerator, et renvoie quelque chose qui peut être utilisé dans foreach.Si le paramètre est un IEnumerator<> la réponse sera un IEnumerable<T>, même si j'appelle GetEnumerator dessus une fois donnera probablement de mauvais résultats.

Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top