05/03/13 00:40:04
>>259
面白そうなのでちょっとILDASMで見てみた。
(2)の最大のボトルネックはCountプロパティの取得部分であるのは動作を見れば一目瞭然。
では内部でどんな作業をしてるのかというと、
1.オーナーであるListViewのCheckedIndicesを取得して、そのCountプロパティを返す。
2.CheckedIndices.Countは、内部ではオーナーであるListViewのItemsプロパティを取得し、
それをFor Eachで回して一つ一つCheckedプロパティを確認し、インクリメントして計測する。
という遠大な事をやっている。
For ... To で毎回Countプロパティを取得してればそりゃ死ねる。
Forの前に一度Countを別変数に取り出すだけで劇的に改善され、(3)にほぼ並ぶ。
さて、(2)と(3)の違いだが。
(2)は毎回Item(Integer)を呼んでいる。この動作の遷移は、
1.ListViewのCheckedIndicesを取得、CheckedIndices.Itemを呼ぶ
2.CheckedIndices.Itemは内部でListView.ItemsをForで回し、Index回目で見つかったCheckedのインデックスを返す
3.返されたインデックスのアイテムをListView.Itemsから取得し、それを返す
という流れだ。分かりにくいなんて意見はスルー。
(3)、For Eachは内部でGetEnumeratorが呼ばれ、それで返されるIEnumeratorのCurrentプロパティ・MoveNextメソッドで列挙動作が行われる。
ではGetEnumeratorはどうなってるかというと、
1.CheckedListViewItemCollection.Countを取得し、その数でListViewItem配列を作成する
2.ListViewのItemsをForで回し、Checkedかどうか確かめてCheckedなアイテムを順に配列に格納する
3.配列のGetEnumeratorを返す
って流れになる。
配列のGetEnumeratorは、MoveNextが呼ばれるごとにインデックスをインクリメントして、Currentで現在のインデックスのアイテムを返すってだけの簡単な処理。
(3)はCheckedListViewItemCollection.Countを取得してる以外にコストがかかる処理はなさそうだ。それが大きいけど。
(2)は2.の所だな。指すインデックスが後ろになればなるほどコストがかかるようになる。
その上ch.Item(ii)がループ回数呼ばれてる訳で、その回数分のListView.Itemsのループが発生してしまうと。
こんな動作を知ってしまった後では、でかいビューでCheckedItemsを使うのは躊躇しちゃうね。