IEnumerable и Рекурсия с помощью возврата урожая

Я имею IEnumerable<T> метод, который я использую для нахождения средств управления на странице WebForms.

Метод является рекурсивным, и у меня есть некоторые проблемы при возврате типа, который я хочу когда yield return returnig значение рекурсивного вызова.

Мой код смотрит следующим образом:

    public static IEnumerable<Control> 
                               GetDeepControlsByType<T>(this Control control)
    {
        foreach(Control c in control.Controls)
        {
            if (c is T)
            {
                yield return c;
            }

            if(c.Controls.Count > 0)
            {
                yield return c.GetDeepControlsByType<T>();
            }
        }
    }

Это в настоящее время бросает, "Не может преобразовать тип выражения" ошибка. Если однако этот метод возвращает тип IEnumerable<Object>, сборки кода, но неправильный тип возвращается в выводе.

Есть ли способ использовать yield return также используя рекурсию?

298
задан Jamie Dixon 13 January 2010 в 00:26
поделиться

4 ответа

Внутри метода, который возвращает IEnumerable, доходность должна возвращать T, а не IEnumerable.

Замените

yield return c.GetDeepControlsByType<T>();

на:

foreach (var x in c.GetDeepControlsByType<T>())
{
  yield return x;
}
480
ответ дан 23 November 2019 в 01:31
поделиться

Вам нужно дать каждый из предметов , полученный рекурсивным вызовом:

public static IEnumerable<Control> GetDeepControlsByType<T>(this Control control)
{
    foreach(Control c in control.Controls)
    {
        if (c is T)
        {
            yield return c;
        }

        if(c.Controls.Count > 0)
        {
            foreach (Control control in c.GetDeepControlsByType<T>())
            {
                yield return control;
            }
        }
    }
}

Обратите внимание, что в этом случае возникает расходы - вы получите создание многих итераторов, которые могут Создайте проблему производительности, если у вас действительно глубокое управление деревом. Если вы хотите избежать этого, вы в основном нужно сделать рекурсию самостоятельно в методе, чтобы убедиться, что создан только один итератор (State Machine). См. Этот вопрос для получения более подробной информации и реализации образца - но это, очевидно, также добавляет определенное количество сложности.

97
ответ дан 23 November 2019 в 01:31
поделиться

Вам нужно вернуть элементы из перечисления, а не сам перечислетель, во второй Доходность возврата

public static IEnumerable<Control> GetDeepControlsByType<T>(this Control control)
{
    foreach (Control c in control.Controls)
    {
        if (c is T)
        {
            yield return c;
        }

        if (c.Controls.Count > 0)
        {
            foreach (Control ctrl in c.GetDeepControlsByType<T>())
            {
                yield return ctrl;
            }
        }
    }
}
12
ответ дан 23 November 2019 в 01:31
поделиться

Внутри метода, возвращающего IEnumerable < T > , доходность return должна возвращать T , а не IEnumerable < T > .

Замените

yield return c.GetDeepControlsByType<T>();

на:

foreach (var x in c.GetDeepControlsByType<T>())
{
  yield return x;
}
-121--548519-

Я бы предложил не беспокоиться о поддержке сборки ascii и юникода (a-la TCHAR) и перейти к юникоду. Это путь вам использовать больше независимых функций платформы (wcscpy, wcsstr и т.д.) вместо того, чтобы полагаться на функции TCHAR , которые специфичны для Micrpsoft.

Вместо std:: string можно использовать std:: string и заменить все char s на wchar _ t s. С таким огромным изменением я обнаружил, что вы начинаете с одной вещи и позволяете компилятору направлять вас к следующей.

Одно, что я могу думать об этом может быть неочевидным во время выполнения, это то, где последовательность назначается с malloc без использования оператора sizeof для базового типа. Поэтому следите за такими вещами, как char * p = (char *) malloc (11) - 10 символов плюс окончание NULL, этот ряд будет вдвое меньше размера, который должен быть в wchar _ t s. Он должен стать wchar _ t * p = (wchar_t*) malloc (11 * sizeof (wchar_t)) .

О, и весь TCHAR должен поддерживать время компиляции ASCII/Unicode последовательностей. Он определён примерно так:

#ifdef _UNICODE
#define _T(x) L ## x
#else
#define _T(x) ## x
#endif

Так, что в конфигурации Юникода _ T («бла») становится L «бла» и в конфигурации ascii это «бла» .

-121--2666503-

Я думаю, что вы должны вернуть каждый из элементов управления в перечнях.

    public static IEnumerable<Control> GetDeepControlsByType<T>(this Control control)
    {
        foreach (Control c in control.Controls)
        {
            if (c is T)
            {
                yield return c;
            }

            if (c.Controls.Count > 0)
            {
                foreach (Control childControl in c.GetDeepControlsByType<T>())
                {
                    yield return childControl;
                }
            }
        }
    }
9
ответ дан 23 November 2019 в 01:31
поделиться
Другие вопросы по тегам:

Похожие вопросы: