Является AsList() лучше, чем ToList () с IDbConnection.Query () который возвращает IEnumerable?
я прочитал этот ответ от Марка Гравелла (@MarcGravell):https://stackoverflow.com/a/47790712/5779732
последняя строка говорит:
в качестве незначительной оптимизации вашего кода: предпочитайте AsList() to ToList (), чтобы избежать создания копии.
это утверждение о QueryMultiple()
возвращает GridReader
.
в моем понимании, System.Linq
предоставляет метод расширения IEnumerable.ToList()
. Ниже Microsoft о ToList()
.
метод ToList(IEnumerable) заставляет немедленную оценку запроса и возвращает список, содержащий результаты запроса. Этот метод можно добавить в запрос для получения кэшированной копии результатов запроса.
IDbConnection.Query()
всегда будет возвращаться IEnumerable
или null
. Null-check можно легко сделать в вызывающем коде. Какая разница AsList
делает тогда?
если мое понимание правильно, AsList
всегда будет внутренне вызов ToList
который создаст копию.
учитывая это, это AsList()
лучше, чем ToList()
С IDbConnection.Query()
возвращает IEnumerable
? Если да, то почему?
что это AsList()
делает ли внутренне это лучший выбор в этом случае?
2 ответов
AsList
- это пользовательский метод расширения Dapper. Все, что он делает, это проверяет, если IEnumerable<T>
вы переходите к нему действительно List<T>
. Если это - он возвращает его обратно, просто бросает в List<T>
. Если это не так - он вызывает regular ToList
. Смысл есть - ToList()
всегда создает копию, даже если то, что вы передаете ей уже список. AsList()
метод избегает делать эту копию, и поэтому полезен, если такая копия не нужна.
в этом конкретном сценарии у вас есть следующее код:
multipleresult.Read<MerchantProduct>()
здесь multipleresult
и GridReader
. Read
и buffered
аргумент, который является true по умолчанию. Когда это правда -Read
действительно вернется List<T>
, путем вызова ToList
вы скопируете этот список снова без особых причин.
то же самое верно для IDbConnection.Query()
- тоже есть buffered
параметр, который является true по умолчанию, поэтому он также по умолчанию возвращает List<T>
.
если вы предпочитаете использовать ToList()
- вы можете передать buffered: false
to Query()
или Read()
чтобы не создавать дополнительные копии.
это расширение является пользовательским расширением dapper, которое делает дополнительную проверку перед вызовом ToList
. источник:
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
или просто не знают разницы. Это опасно, если кто-то изменит код позже.
так, например, метод, который принимает IEnumerable<T>
использует AsList
:
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
метод. Вы всегда можете проверить тип самостоятельно.