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