Почему коллекция 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();

person Earlz    schedule 21.07.2010    source источник
comment
Вы можете сделать list.SingleOrDefault(x => x.ID == "Some ID");   -  person Yuriy Faktorovich    schedule 21.07.2010


Ответы (4)


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

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

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

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

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

person Jon Skeet    schedule 21.07.2010

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

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

var c = Controls.Cast<Control>().Where(x => x.ID == "Some ID").SingleOrDefault();
person Dan Tao    schedule 21.07.2010
comment
Есть ли причина, по которой он не был обновлен для реализации IEnumerable<Control>? Это не должно нарушать обратную совместимость. - person Vapid Linus; 23.03.2020

В дополнение к ответам, предоставленным Джоном Скитом и Дэном Тао, вы можете использовать синтаксис выражения запроса, явно указав тип.

Control myControl = (from Control control in this.Controls
                    where control.ID == "Some ID"
                    select control).SingleOrDefault();
person Anthony Pegram    schedule 21.07.2010

Linq использовал общие коллекции. ControlsCollection реализует IEnumerable, а не 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();
person CkH    schedule 21.07.2010