Могу ли я иметь метод, возвращающий IEnumerator и использовать его в цикле 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;
        }
    }
}

Используя это так:

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

Но, конечно, компилятор плюет на свою пустышку, потому что foreach ожидает IEnumerable, а не IEnumerator .

Есть ли способ сделать это без необходимости создания отдельного класса с помощью метода GetEnumerator () ?

6.08.2008 12:17:31
На самом деле, foreachне ожидает IEnumerableвообще (ни IEnumerable<T>). Ожидается только то, что имеет GetEnumeratorметод. Этот метод, в свою очередь, не обязательно должен возвращать IEnumeratorили IEnumerator<T>- он должен возвращать только то, что имеет MoveNext()метод и Currentсвойство.
Timwi 1.09.2010 14:22:53
5 ОТВЕТОВ
РЕШЕНИЕ

Как говорит вам компилятор, вам нужно изменить тип возвращаемого значения на IEnumerable. Вот как работает синтаксис yield return.

14
6.08.2008 12:19:57
yield returnможно использовать с методами , которые возвращают либо IEnumerable<T> или IEnumerator<T> . Это только в foreachцикле, где IEnumerator<T>нельзя использовать.
Timwi 1.09.2010 14:20:53
// 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;
    }
}
1
31.08.2015 16:10:40

Если вы вернете IEnumerator, он будет другим объектом перечислителя при каждом вызове этого метода (действуя так, как будто вы сбрасываете перечислитель на каждой итерации). Если вы возвращаете IEnumerable, то foreach может перечислять на основе метода с оператором yield.

3
6.08.2008 13:04:33

Чтобы уточнить

private static IEnumerator<TextBox> FindTextBoxes(Control rootControl)

Изменения к

private static IEnumerable<TextBox> FindTextBoxes(Control rootControl)

Это должно быть все :-)

10
8.08.2008 23:34:44

Если вы получили перечислитель и вам нужно использовать его в цикле for-each, вы можете использовать следующее для его переноса:

статическое перечисление public classHelper
{
    открытый класс enumeratorHolder <T>
    {
        частный счетчик;
        public T GetEnumerator () {вернуть theEnumerator; }
        public enumeratorHolder (T newEnumerator) {theEnumerator = newEnumerator;}
    }
    статический enumeratorHolder <T> toEnumerable <T> (T theEnumerator) {вернуть новый enumeratorHolder <T> (theEnumerator); }
    закрытый класс IEnumeratorHolder <T>: IEnumerable <T>
    {
        закрытый IEnumerator <T> theEnumerator;
        public IEnumerator <T> GetEnumerator () {вернуть theEnumerator; }
        System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator () {вернуть theEnumerator; }
        public IEnumeratorHolder (IEnumerator <T> newEnumerator) {theEnumerator = newEnumerator; }
    }
    статический IEnumerable <T> toEnumerable <T> (IEnumerator <T> theEnumerator) {вернуть новый IEnumeratorHolder <T> (theEnumerator); }
}

toEnumerableМетод будет принимать что - либо , что или бы расценить приемлемый тип возвращаемого из GetEnumerator, и вернуть то , что может быть использовано в foreach. Если параметр является IEnumerator<>ответом, будет ответом IEnumerable<T>, хотя вызов GetEnumeratorего один раз, скорее всего, даст плохие результаты.

0
31.08.2015 16:11:33