Почему коллекция Controls не предоставляет все методы IEnumerable? - PullRequest
36 голосов
/ 21 июля 2010

Я не уверен, как работает 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();

Ответы [ 4 ]

71 голосов
/ 21 июля 2010

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

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

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

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

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

8 голосов
/ 21 июля 2010

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

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

var c = Controls.Cast<Control>().Where(x => x.ID == "Some ID").SingleOrDefault();
4 голосов
/ 21 июля 2010

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

Control myControl = (from Control control in this.Controls
                    where control.ID == "Some ID"
                    select control).SingleOrDefault();
2 голосов
/ 21 июля 2010

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

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

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

Однако, это работает

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

.IEnumerable<T> или получите доступ к методу расширения, который делает, например, так:

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