2008年08月01日

OfType演算子

   このエントリーをはてなブックマークに追加 Clip to Evernote
前回の記事の

var buttons = this.Controls.Cast<Control>().Where(ctrl => ctrl is Button);

は、OfType演算子を使えば、

var buttons = this.Controls.Cast<Control>().OfType<Button>();

でOKでした。これで指定した型のオブジェクトだけを抜き出してくれます。

--------------
8/4追記

さらに短くできました。

var buttons = this.Controls.OfType<Button>();


と、OfTypeだけで良いんですね。






この記事へのコメント
Cast<T> と OfType<T> は、「目的の型にキャストできないものが
IEnumerable 内にあった場合にどうするか」で使い分けるものだと
思います。

・キャストできないものがあったら例外を発生させたい場合は Cast<T>
var buttons = this.Controls.Cast<Button>();

・キャストできないものをスキップする場合は OfType<T>
var buttons = this.Controls.OfType<Button>();
Posted by hzc at 2008年08月02日 02:40
> ・キャストできないものがあったら例外を発生させたい場合は Cast<T>
> var buttons = this.Controls.Cast<Button>();

とのことですが、MSDNには
Cast<(Of <(TResult>)>)(IEnumerable) メソッドを使用すると、必要な型情報を指定することで、非ジェネリック コレクションに対して標準クエリ演算子を呼び出すことができます

とあります。
たしかに、指定した型にキャストできないと、実行時例外が発生しますが、
非ジェネリックスコレクションかそうでないかが、基準になると認識しています。

> ・キャストできないものをスキップする場合は OfType<T>
> var buttons = this.Controls.OfType<Button>();

これは、おっしゃるとおりであり、
結局、指定した型(あるいはその派生型)だけを抜き取る
操作になります。

どちらにせよ、Controlsプロパティに対し、LINQ演算子を使えるように
するには、Cast演算子を使うことになるのではと思います。
Posted by gushwell at 2008年08月02日 09:47
OfType も「this IEnumerable」を引数にとるので、
Cast<T>().OfType<U>() のような使用は冗長ではないか?

というようなことを言おうとしたのですが、上記のコメントは
回りくどく、分かり辛いものになってしましました、すみません。

「タイプパラメータ無しの IEnumerable をタイプパラメータ付きの
IEnumerable<T>に変換して、クエリ演算子を使えるようにするときに、
Cast と OfType のどちらを使うべきか」

ということを前提にして上記のコメントを読んでいただけると
より分かり易いかと思います。
Posted by hzc at 2008年08月02日 14:47
やっと理解できました。(^^;
非ジェネリックスのIEnumerableに対して、どちらを使うか
ということですね。
僕の頭が、一つ前の記事の話とごっちゃになっていたので...
頭が固くていけませんね。

OfTypeも非ジェネリックスのIEnumerableを引数に取るので
確かに、この場合Cast<>は不要ですね。
どうもありがとうございました。

Posted by Gushwell at 2008年08月02日 15:15
 

この記事へのトラックバックURL

http://trackback.blogsys.jp/livedoor/gushwell/51586630