web-dev-qa-db-ja.com

ControlsコレクションがすべてのIEnumerableメソッドを提供しないのはなぜですか?

ASP.NetのControlCollectionがどのように機能するかわからないので、誰かが私のためにこれに光を当てることができるかもしれません。

最近、拡張メソッドと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();
38
Earlz

いいえ、IEnumerableには多くの拡張メソッドがありません:_IEnumerable<T>_にはあります。 _IEnumerable<T>_はIEnumerableを拡張しますが、これらは2つの別個のインターフェースです。

変換の通常のLINQ方法は、 Cast<T>() および OfType<T>() 拡張メソッドを使用することです。 )do非汎用インターフェースを拡張します:

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

2つの違いは、OfTypeは必要なタイプではないアイテムをスキップするだけであるということです。 Castは代わりに例外をスローします。

一般的な_IEnumerable<T>_タイプへの参照を取得すると、残りのすべてのLINQメソッドを使用できるようになります。

78
Jon Skeet

これは、 ControlCollection クラスがジェネリックスの前に登場したからです。したがって、IEnumerableを実装しますが、IEnumerable<Control>は実装しません。

幸い、IEnumerableインターフェイスにはLINQ拡張メソッドがあり、キャストによってIEnumerable<T>生成できます。 Cast<T> 。つまり、いつでもこれを行うことができます。

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

JonSkeetとDanTaoによって提供された回答に加えて、型を明示的に指定することにより、クエリ式の構文を使用できます。

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

Linqはジェネリックコレクションを利用しました。 ControlsCollectionは、IEnumberable<T>ではなくIEnumerableを実装します

これが機能しないことに気付いた場合

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

しかし、これは

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

Generic IEnumerable<T>にキャストするか、次のように拡張メソッドにアクセスできます。

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