Я имею 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
также используя рекурсию?
Внутри метода, который возвращает IEnumerable
, доходность
должна возвращать T
, а не IEnumerable
.
Замените
yield return c.GetDeepControlsByType<T>();
на:
foreach (var x in c.GetDeepControlsByType<T>())
{
yield return x;
}
Вам нужно дать каждый из предметов , полученный рекурсивным вызовом:
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). См. Этот вопрос для получения более подробной информации и реализации образца - но это, очевидно, также добавляет определенное количество сложности.
Вам нужно вернуть элементы из перечисления, а не сам перечислетель, во второй Доходность возврата
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;
}
}
}
}
Внутри метода, возвращающего 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 это «бла»
.
Я думаю, что вы должны вернуть каждый из элементов управления в перечнях.
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;
}
}
}
}