Является 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 метод. Вы всегда можете проверить тип самостоятельно.