web-dev-qa-db-ja.com

AsList()は、IEnumerableを返すIDbConnection.Query()を使用するToList()よりも優れていますか?

私はMarcGravell(@MarcGravell)からこの回答を読みました: https://stackoverflow.com/a/47790712/5779732

最後の行は言う:

コードのマイナーな最適化として:コピーの作成を避けるために、ToList()よりもAsList()を優先します。

そのステートメントは、GridReaderを返すQueryMultiple()に関するものです。

私の理解では、_System.Linq_は拡張メソッドIEnumerable.ToList()を提供します。以下は MicrosoftToList()についてです。

ToList(IEnumerable)メソッドは、クエリの即時評価を強制し、クエリ結果を含むリストを返します。クエリ結果のキャッシュされたコピーを取得するために、このメソッドをクエリに追加できます。

IDbConnection.Query()は常にIEnumerableまたはnullを返します。ヌルチェックは、コードを呼び出すときに簡単に実行できます。 AsListはどのような違いをもたらしますか?

私の理解が正しければ、AsListは常に内部的にToListを呼び出し、コピーを作成します。

これを考慮すると、AsList()IEnumerableを返すToList()を使用するIDbConnection.Query()よりも優れていますか?もし、そうなら;どうして?

AsList()が内部的に行うことは何ですか?この場合、それはより良い選択になりますか?

9
Amit Joshi

AsListはカスタムDapper拡張メソッドです。渡すのは_IEnumerable<T>_が本当に_List<T>_であるかどうかをチェックするだけです。もしそうなら-それはそれを返します、ただ_List<T>_にキャストします。そうでない場合は、通常のToListを呼び出します。重要なのは-ToList()は、渡したものがすでにリストであっても、常にコピーを作成します。 AsList()メソッドはこのコピーを回避するため、このようなコピーが不要な場合に役立ちます。

この特定のシナリオでは、次のコードがあります。

_multipleresult.Read<MerchantProduct>()
_

ここで、multipleresultGridReaderです。 Readにはbuffered引数があります。これはデフォルトでtrueです。真の場合-Readは実際に_List<T>_を返すので、ToListを呼び出すことにより、理由もなくそのリストを再度コピーします。

同じことがIDbConnection.Query()にも当てはまります。bufferedパラメータもあります。これはデフォルトでtrueであるため、デフォルトで_List<T>_も返されます。

ToList()を使用したい場合は、_buffered: false_をQuery()またはRead()に渡して、追加のコピーが作成されないようにすることができます。

11
Evk

この拡張機能は、ToListを呼び出す前に追加のチェックを行うカスタムdapper拡張機能です。 ソース

public static List<T> AsList<T>(this IEnumerable<T> source) 
    => (source == null || source is List<T>) ? (List<T>)source : source.ToList();
  • ToListは常に新しいList<T>インスタンスを作成し、指定されたアイテムで埋めます
  • AsListはシーケンスがすでにList<T>であるかどうかをチェックし、それをキャストするだけです

もちろん、何かをキャストすることは、何か新しいものを作成して埋めるよりもはるかに少ない作業であるため、このアプローチはより効率的です。ですから、それは完全に異なります。

これは一種の意見に基づいていますが、私はこれが危険だと思います。誰かがAsListを見落とし、ToListを読んだり、違いがわからなかったりする可能性があります。後で誰かがコードを変更すると危険です。

したがって、たとえば、AsListを使用するIEnumerable<T>を受け取るメソッド:

public static List<T> GetResult<T>(IEnumerable<T> seq)
{
    if(some condition here)
    {
        seq = seq.Where(some predicate here);
    }
    return seq.AsList()
}

ここで、コードはリストを使用してこのメ​​ソッドを呼び出しました。

IEnumerable<string> sequence = (gets a list from somewhere)
List<string> userList = GetResult(sequence);

後で誰かがここで配列がより適切であると決定します:

IEnumerable<string> sequence = (gets an array from somewhere)
List<string> userList = GetResult(sequence);

これは今まで本当に害はありません。ソースがリストではなく、キャストできないため、新しいリストが初期化されて入力されます。したがって、効率が低下します。ただし、ロジックが同じ参照であるリストにも依存している場合、これは機能しなくなります。

if(userList == seq)
{
    // do something
}

配列が使用されると、これは常にfalseになります。そのため、コードは黙って壊れていました。

長い話を短くするために:私はAsListメソッドが好きではありません。タイプはいつでも自分で確認できます。

2
Tim Schmelter