C#リスト< T> vs IEnumerable< T>パフォーマンスの質問
-
06-07-2019 - |
質問
こんにちは、これらの2つのメソッドを想定しています:
private List<IObjectProvider> GetProviderForType(Type type)
{
List<IObjectProvider> returnValue = new List<IObjectProvider>();
foreach (KeyValuePair<Type, IObjectProvider> provider in _objectProviders)
{
if ((provider.Key.IsAssignableFrom(type) ||
type.IsAssignableFrom(provider.Key)) &&
provider.Value.SupportsType(type))
{
returnValue.Add(provider.Value);
}
}
return returnValue;
}
private IEnumerable<IObjectProvider> GetProviderForType1(Type type)
{
foreach (KeyValuePair<Type, IObjectProvider> provider in _objectProviders)
if ((provider.Key.IsAssignableFrom(type) ||
type.IsAssignableFrom(provider.Key)) &&
provider.Value.SupportsType(type))
yield return provider.Value;
}
どちらが速いですか?最初の方法を見ると、メモリがListに割り当てられていることがわかりますが、これは必要ないと思われます。 IEnumerable メソッドの方が速いようです。
たとえば、あなたが呼び出すと仮定します
int a = GetProviderForType(myType).Count;
int b = GetProviderForType1(myType).Count();
今、別の問題は、上記の2つの間にパフォーマンスの違いがありますか?
あなたはどう思いますか
解決
この特定のケースでは、カウントを知る必要があるのはのみであるため、 IEnumerable&lt; T&gt;
フォームを使用する方が効率的です。データを保存したり、バッファのサイズを変更したりする必要はありません。
何らかの理由で結果を再度使用する必要がある場合、 List&lt; T&gt;
フォームの方が効率的です。
List&lt; T&gt;
では、 Count()
拡張メソッドと Count
プロパティの両方が、< code> Count()は、ターゲットシーケンスが ICollection&lt; T&gt;
を実装しているかどうかを確認し、実装している場合は Count
プロパティを使用します。
さらに効率的でなければならない別のオプションは、 効率的です(ただ)が、デリゲートを取る Count
のオーバーロードを呼び出すことです:
private int GetProviderCount(Type type)
{
return _objectProviders.Count(provider =>
(provider.Key.IsAssignableFrom(type)
|| type.IsAssignableFrom(provider.Key))
&& provider.Value.SupportsType(type));
}
これにより、 Where
句と Select
句によって生じる余分なレベルの間接参照が回避されます。
(マークが言うように、少量のデータの場合、パフォーマンスの違いはおそらくとにかく無視できるでしょう。)
他のヒント
このような質問に対する正確な答えは、多くの要因によって異なり、CLRが進化するにつれてさらに変化する可能性があります。確認する唯一の方法は、それを測定することです。これが現れる操作と比較して差が小さい場合は、最も読みやすく、保守しやすい書き方を選択する必要があることに留意してください。
そしてそのメモで、あなたも試してみたいと思うかもしれません:
private IEnumerable<IObjectProvider> GetProviderForType1(Type type)
{
return _objectProviders.Where(provider =>
provider.Key.IsAssignableFrom(type) ||
type.IsAssignableFrom(provider.Key)) &&
provider.Value.SupportsType(type))
.Select(p => p.Value);
}
IEnumerable&lt; T&gt;
を返し、「スナップショット」したい場合は ToList
拡張メソッドを使用することで、柔軟性を高めることもできます。結果をリストに。これにより、リストを複数回調べる必要がある場合に、コードを繰り返し評価してリストを生成することを回避できます。
この質問の重要な部分は、「データの大きさ」です。行数...
少量のデータの場合、リストは問題ありません-十分な大きさのリストを割り当てるのにごくわずかな時間しかかかりません。 / p>
ただし、これは膨大なデータ量に対応していません。あなたのプロバイダーが何千ものインターフェースをサポートしているとは思えないので、このモデルに行くのは必要とは言いませんが、大した被害はありません。
もちろん、LINQも使用できます。
return from provider in _objectProviders
where provider.Key.IsAssignableFrom(type) ...
select provider.Value;
これは、隠れた yield
のアプローチでもあります...
IEnumerableとIListの主な違い:
IEnumerable: MoveNext、Reset、Get Currentメソッドを実装し、反復するIEnumeratorのタイプを返します レコードを使用。
IList:IEnumerableインターフェイスを公開します。これは、インデックスを介してアクセスできる非ジェネリックオブジェクトのコレクションでもあるため、IEnumerable + ICollection(データの操作)およびadd、remove、Insert(特定のインデックスで)が便利ですIListによって実装されるメソッド。
自分の意見でコードを確認した後、IEnumerableはより効率的ですが、データを操作したい場合や、データを反復処理したい場合はIEnumerableが望ましいです。