C#+WPFチューニング戦記

C#とWPFで高速なコードと最適なシステムを書くためにやってきたいろいろな事を書いてみます。.NET Frameworkのソースコードを読み解きましょう。なお、ここに書かれているのは個人の見解であって何らかの団体や企業の見解を代表するものではありません。

半端にLINQを使う悪手の代表例

古式なC#ですと、ループして、条件を絞り込む書き方が一般的でした。

// 例:1

foreach( var item in Items ) {

    if( item.Value > 10.0 ) {

         // 何かの処理

    }

いやぁ、懐かしい。

LINQの登場(というか、メソッドチェインとラムダ式の導入)によって書き方は激変し、このように書くことができます。

// 例:2

Items.Where(item=>item.Value>10.0)

         .ForEach(item=> /* 何かの処理 */); 

 短くまとまって、ループ回数も最小でハッピーです。この書き方は今や当たり前というくらいに浸透しています。

ところで、先日LINQがIEnumerable<TSource>を最適化しているだのということを書きましたが、古い構文との相性はさほど良くないことは書いておかなければならないことを思い出しました。

// 例:3

foreach( var item in Items.Where( e => e.Value > 10.0) )  {

    // 何かの処理

}

 速度の順序では、特殊な事例でなければ普通では1→3→2となります。ただし、ForEachは実は書き方次第でWhereと組み合わせて高速なコードを書くことができるので、1には届きませんが、2と3の順位は実装次第です。2は.NET Frameworkメソッドチェイン標準実装のWhere+Selectの工夫のように、高速化余地が多々あるのでまだ有望です。

しかし3については、古い文法と混在していると、そこはコード展開が、2か所で遅いほうのIEnumerable<TSource>になってしまい、最適化の恩恵も最小になってしまいます。

どう直してもまず1には及ばないのですから、3で書くくらいなら1で書いたほうが潔いとも言えます。

古い書き方との混在は、コンパイラによる最適化の余地をつぶしてしまう可能性があります。気を付けましょう。

 

LINQに慣れた(いまどき普通の)C#プログラマにとっては、この点は色々とコードレビューもあるかと思いますので、ちゃんとコメントで理由を付記することをお忘れなく。