IEnumerable<>
一般的に、パラメータを渡すときは 型としてを使用する傾向があります。ただし、BenchmarkDotNet によると:
[Benchmark]
public void EnumeratingCollectionsBad()
{
var list = new List<string>();
for (int i = 0; i < 1000; i++)
{
Bad(list);
}
}
[Benchmark]
public void EnumeratingCollectionsFixed()
{
var list = new List<string>();
for (int i = 0; i < 1000; i++)
{
Fixed(list);
}
}
private static void Bad(IEnumerable<string> list)
{
foreach (var item in list)
{
}
}
private static void Fixed(List<string> list)
{
foreach (var item in list)
{
}
}
方法 | 仕事 | ランタイム | 平均 | エラー | 標準偏差 | 中央値 | 世代 0 | 第1世代 | 第2世代 | 割り当て済み |
---|---|---|---|---|---|---|---|---|---|---|
コレクションの列挙が不正 | .NET Core 3.1 | .NET Core 3.1 | 17.802 米ドル | 0.3670 米ドル | 1.0764 米ドル | 17.338 米ドル | 6.3782 | - | - | 40032B |
コレクションの列挙固定 | .NET Core 3.1 | .NET Core 3.1 | 5.015 米ドル | 0.1003 米 | 0.2535 米ドル | 4.860 米ドル | - | - | - | 32 B |
インターフェース バージョンは、具体的なバージョンよりもはるかに遅く (メモリを大量に消費) なるのはなぜでしょうか?
ベストアンサー1
インターフェース バージョンは、具体的なバージョンよりもはるかに遅く (メモリを大量に消費) なるのはなぜでしょうか?
インターフェースを使用する場合、反復処理ではヒープ上にオブジェクトを割り当てる必要があります...一方、List<T>.GetEnumerator()
は構造体である を返しList<T>.Enumerator
、追加の割り当てを必要としません。List<T>.Enumerator
を実装しますIEnumerator<T>
が、コンパイラは具体的な型を直接認識するため、ボックス化する必要はありません。
したがって、両方のメソッドが同じ型 (a ) のオブジェクトに対して操作している場合でも、List<T>
次のメソッドを呼び出します。
IEnumerator<T> GetEnumerator()
...そしてこれをこう呼ぶ人もいる:
List<T>.Enumerator GetEnumerator()
IEnumerator<T>
最初のものはほぼ間違いなく 2 番目のものに委任するだけですが、参照型であるため、結果をボックス化する必要があります。
List<T>.GetEnumerator()
可変構造体を返すという事実驚くべき結果をもたらす可能性があるしかし、これはまさにここでご覧になっているパフォーマンス上の利点が得られるように設計されています。
インターフェースと具体的な型の使用できるそれ自体にはごくわずかなパフォーマンスの低下がありますが、ここでの主な原因は割り当ての違いです。