Pourquoi la collection Controls ne fournit-elle pas toutes les méthodes IEnumerable?

Je ne suis pas sûr de savoir comment le ControlCollection de ASP.Net fonctionne, alors peut-être que quelqu'un peut faire la lumière sur cela pour moi.

J'ai récemment découvert la magie qu'est les méthodes d'extension et Linq. Eh bien, j'étais très triste de constater que ce n'est pas une syntaxe valide

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

Cependant, d'après ce que je peux dire, Controls implémente l'interface IEnumerable qui fournit de telles méthodes, alors qu'est-ce qui donne? Pourquoi n'est-elle pas juste travailler? J'ai trouvé un travail décent pour ce problème au moins:

var list = (IEnumerable<Control>)Controls;
var this_item = list.Where(x => x.ID == "Some ID").SingleOrDefault();
30
demandé sur Earlz 2010-07-21 22:17:49

4 réponses

Non, IEnumerable n'a pas beaucoup de méthodes d'extension: IEnumerable<T> fait. Ce sont deux interfaces distinctes, bien que IEnumerable<T> s'étende IEnumerable.

Les méthodes normales de conversion de LINQ sont d'utiliser Cast<T>() et OfType<T>() méthodes d'extension quifont étendre l'interface non générique:

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

La différence entre les deux est que OfType ignorera simplement tous les éléments qui ne sont pas du type requis; Cast lancera une exception à la place.

Une fois vous avez des références au type générique IEnumerable<T>, tout le reste des méthodes LINQ sont disponibles.

62
répondu Jon Skeet 2010-07-21 18:20:17

C'est juste parce que le ControlCollection la classe est venue avant les génériques; donc elle implémente IEnumerable mais pas IEnumerable<Control>.

Heureusement, il existe une extension LINQ méthode sur la IEnumerable interface qui vous permet de générer un IEnumerable<T> par moulage: Cast<T>. Ce qui signifie que vous pouvez toujours faire ceci:

var c = Controls.Cast<Control>().Where(x => x.ID == "Some ID").SingleOrDefault();
8
répondu Dan Tao 2010-07-21 18:22:04

En plus des réponses fournies par Jon Skeet et Dan Tao, vous pouvez utiliser la syntaxe d'expression de requête en fournissant explicitement le type.

Control myControl = (from Control control in this.Controls
                    where control.ID == "Some ID"
                    select control).SingleOrDefault();
4
répondu Anthony Pegram 2010-07-21 18:32:18

Linq a utilisé des Collections génériques. ControlsCollection implémente IEnumerable pas IEnumberable<T>

Si vous remarquez que cela ne fonctionnera pas

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

Cependant, cela fait

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

Vous pouvez soit convertir en Générique IEnumerable<T> ou accéder à une méthode d'extension qui le fait, comme ceci:

 page.Controls.OfType<Control>().Where(c => c.ID == "Some ID").FirstOrDefault();
2
répondu CkH 2010-07-21 18:38:07