web-dev-qa-db-ja.com

foreach in listまたはforeach in list.where

私はこの質問を何と呼ぶべきか分かりません。

これは私の例です:

foreach (var item in lstItem.Where(item => stock.ItemCode == item.ItemCode))
{
     stock.ItemName = item.ItemName;
     stock.ItemUnitName = item.ItemUnitName;
     stock.BrandName = item.BrandName;
     stock.FamilyName = item.FamilyName;
}

または

// Assume list has items
var list = lstItem.Where(item => stock.ItemCode == item.ItemCode);
foreach (var item in list)
{
     stock.ItemName = item.ItemName;
     stock.ItemUnitName = item.ItemUnitName;
     stock.BrandName = item.BrandName;
     stock.FamilyName = item.FamilyName;
}

どちらがいいですか?

1
Steve Lam

ここでは、2つの興味深い質問が1つにまとめられています。

最初に、より複雑な式をより単純な式に分割し、変数に役立つ名前を付ける機会を利用する方が良いでしょうか?

これは多くの場合非常に優れたアイデアですが、この場合、コードは次のように読みやすくなります。

var wanted_items = lstItem.Where(item => stock.ItemCode == item.ItemCode);
foreach (var item in wanted_items)

次に、このような表現を分解する際にパフォーマンスの問題はありますか?

一般的なケースでは、答えるのは簡単ではありません。ほとんどの言語では、この種の構成により、リストのすべての項目が処理されて必要な項目が除外され、次に個々の項目が再び処理されて割り当てが適用されます。一致が1つしかない場合、最初のパスで(平均して)必要な数の2倍の項目が検査されます。

しかし、これはC#とLinqなので、リストはイテレータになるか、SQLに変換されます。どちらも処理を最適化しますが、程度は異なります。この特定のケースでは、式が分割されてもされなくても、パフォーマンスはまったく同じになるはずですが、このように式を分割すると、特定のパスが実行のために結晶化し、パフォーマンスに非常に深刻な影響を与える可能性がある密接に関連する構造があります。

最終的には、可能な限り最高のアルゴリズムと、基盤となるフレームワークライブラリの可能な限り最高の使用を使用して、最も読みやすいコードを常に記述する必要があります。パフォーマンスに懸念がある場合は、コードの変更を検討する前に、ベンチマークと測定を行う必要があります。

0
david.pfx

どちらの例も機能的に同等です。

これは、列挙が絶対に必要になるまで列挙が評価されないためです。 2番目の例を見てください。

_var list = lstItem.Where(item => stock.ItemCode == item.ItemCode);
foreach (var item in list)
{
 stock.ItemName = item.ItemName;
 stock.ItemUnitName = item.ItemUnitName;
 stock.BrandName = item.BrandName;
 stock.FamilyName = item.FamilyName;
}
_

何が起きるかは、listがリストではないということです。むしろ、それはWhere条件が設定されたlstItemの列挙子です。その列挙子は、foreachループの反復ごとに1回評価されます。

これは、foreachループが早期に終了した場合に最大のパフォーマンスが得られるためです。列挙子は、実行時に複雑な計算を行う必要がある場合があるため、短絡が原因で、コードがはるかに高速になる場合があります。

var list = lstItem.Where(item => stock.ItemCode == item.ItemCode);をリストとして提供することを考えないことが最善です。むしろ、アイテムがなくなるまで要求されたときに次のアイテムを返すオブジェクトを提供しています。理論的には永遠に続く可能性があり、それ自体を循環する列挙子を書くことは完全に可能です。

個人的には、最初のコードスニペットをお勧めします。コンパイラーがコードを最適化すると、後で使用されない限り、一時的なlist変数が最適化されます。

1
Stephen