Подтвердить что ты не робот

Почему коллекция Controls не предоставляет все методы IEnumerable?

Я не уверен, как работает ControlCollection ASP.Net, поэтому, возможно, кто-то может пролить свет на это для меня.

Недавно я обнаружил магию, которая является методом расширения и Linq. Ну, мне было очень грустно найти, что это недопустимый синтаксис

var c=Controls.Where(x => x.ID=="Some ID").SingleOrDefault();

Однако из того, что я могу сказать, Controls реализует интерфейс IEnumerable, который предоставляет такие методы, и что дает? Почему это не работает? По крайней мере, я нашел достойную работу по этой проблеме:

var list = (IEnumerable<Control>)Controls;
var this_item = list.Where(x => x.ID == "Some ID").SingleOrDefault();
4b9b3361

Ответ 1

Нет, IEnumerable не имеет на нем много методов расширения: IEnumerable<T> делает. Это два отдельных интерфейса, хотя IEnumerable<T> extends IEnumerable.

Нормальными способами конвертации LINQ являются использование Cast<T>() и OfType<T>(), которые расширяют нелинейный интерфейс:

IEnumerable<TextBox> textBoxes = Controls.OfType<TextBox>();
IEnumerable<Control> controls = Controls.Cast<Control>();

Разница между двумя заключается в том, что OfType будет просто пропускать любые элементы, которые не являются требуемым типом; Cast вместо этого генерирует исключение.

После того, как вы получили ссылки на общий тип IEnumerable<T>, все остальные методы LINQ доступны.

Ответ 2

Это происходит только потому, что класс ControlCollection появился перед дженериками; поэтому он реализует IEnumerable, но не IEnumerable<Control>.

К счастью, существует метод расширения LINQ на интерфейсе IEnumerable, который позволяет вам генерировать IEnumerable<T> посредством кастинга: Cast<T>. Это означает, что вы всегда можете просто сделать это:

var c = Controls.Cast<Control>().Where(x => x.ID == "Some ID").SingleOrDefault();

Ответ 3

В дополнение к ответам, предоставленным Jon Skeet и Dan Tao, вы можете использовать синтаксис выражения запроса, явно предоставляя тип.

Control myControl = (from Control control in this.Controls
                    where control.ID == "Some ID"
                    select control).SingleOrDefault();

Ответ 4

Linq использовал общие коллекции. ControlsCollection реализует IEnumerable not IEnumberable<T>

Если вы заметили, что это не сработает

((IEnumerable)page.Controls).Where(...

Однако это делает

((IEnumerable<Control>)page.Controls).Where(...

Вы можете либо передать в Generic IEnumerable<T>, либо получить доступ к методу расширения, который делает это:

 page.Controls.OfType<Control>().Where(c => c.ID == "Some ID").FirstOrDefault();