Могу ли я создать метод, возвращающий IEnumerator<T> , и использовать его в цикле foreach?

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

Вопрос

Мне нужно установить высоту каждого текстового поля в моей форме, некоторые из которых вложены в другие элементы управления.Я думал, что смогу сделать что-то подобное:

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

Но, конечно, компилятор выдает свой фиктивный файл, потому что предначертание ожидает, что IEnumerable ( количество ) вместо того , чтобы IEnumerator ( нумератор ).

Есть ли способ сделать это без необходимости создавать отдельный класс с GetEnumerator() способ?

Это было полезно?

Решение

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

Другие советы

Просто чтобы прояснить

private static IEnumerator<TextBox> FindTextBoxes(Control rootControl)

Изменения в

private static IEnumerable<TextBox> FindTextBoxes(Control rootControl)

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

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

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

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

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

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

Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top