Kann ich eine Methode haben, die IEnumerator<T> zurückgibt, und sie in einer foreach-Schleife verwenden?

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

Frage

Ich muss die Höhe jedes Textfelds in meinem Formular festlegen, von dem einige in anderen Steuerelementen verschachtelt sind.Ich dachte, ich könnte so etwas machen:

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

Benutze es so:

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

Aber natürlich spuckt der Compiler seinen Dummy aus, denn für jede erwartet eine IEnumerable eher als ein IEnumerator.

Gibt es eine Möglichkeit, dies zu tun, ohne eine separate Klasse mit a erstellen zu müssen? GetEnumerator() Methode?

War es hilfreich?

Lösung

Wie der Compiler Ihnen mitteilt, müssen Sie Ihren Rückgabetyp in IEnumerable ändern.So funktioniert die Yield-Return-Syntax.

Andere Tipps

Nur um klarzustellen

private static IEnumerator<TextBox> FindTextBoxes(Control rootControl)

Änderungen an

private static IEnumerable<TextBox> FindTextBoxes(Control rootControl)

Das sollte alles sein :-)

Wenn Sie IEnumerator zurückgeben, handelt es sich bei jedem Aufruf dieser Methode um ein anderes Enumeratorobjekt (was so wirkt, als ob Sie den Enumerator bei jeder Iteration zurücksetzen würden).Wenn Sie IEnumerable zurückgeben, kann ein foreach basierend auf der Methode mit der yield-Anweisung eine Aufzählung durchführen.

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

Wenn Sie einen Enumerator erhalten und ihn in einer for-each-Schleife verwenden müssen, können Sie ihn wie folgt umschließen:

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

Der toEnumerable Die Methode akzeptiert alles, was das bedeutet oder würde einen akzeptablen Rückgabetyp von betrachten GetEnumerator, und etwas zurückgeben, das verwendet werden kann foreach.Wenn der Parameter ein ist IEnumerator<> Die Antwort wird eine sein IEnumerable<T>, obwohl anrufen GetEnumerator Wenn Sie es einmal anwenden, wird dies wahrscheinlich zu schlechten Ergebnissen führen.

Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top