我从Marc Gravell(@MarcGravell)读到这个答案:https://stackoverflow.com/a/47790712/5779732
最后一行说:
作为对代码的次要优化:首选AsList()到ToList()以避免创建副本。
该声明约为QueryMultiple()
,返回GridReader
。
据我了解,System.Linq
提供了一种扩展方法IEnumerable.ToList()
。以下内容来自Microsoft关于ToList()
。
ToList(IEnumerable)方法强制立即进行查询评估,并返回包含查询结果的List。您可以将此方法附加到查询中,以获取查询结果的缓存副本。
IDbConnection.Query()
将始终返回IEnumerable
或null
。在调用代码时可以轻松完成空检查。那么AsList
会有什么不同呢?
如果我的理解是正确的,AsList
将始终在内部调用ToList
来创建副本。
考虑到这一点,AsList()
优于ToList()
而IDbConnection.Query()
返回IEnumerable
?如是;为什么呢?
在这种情况下,AsList()
内部是什么使它成为更好的选择?
答案 0 :(得分:10)
AsList
是一种自定义Dapper扩展方法。它所做的就是检查传递给它的IEnumerable<T>
是否真的List<T>
。如果是 - 它返回它,只是转换为List<T>
。如果不是 - 它会定期调用ToList
。关键是 - ToList()
总是创建一个副本,即使你传递给它的是一个列表。 AsList()
方法避免执行此副本,因此如果不需要此类副本,则非常有用。
在此特定方案中,您有以下代码:
multipleresult.Read<MerchantProduct>()
其中multipleresult
为GridReader
。 Read
具有buffered
参数,默认情况下为true。如果真实 - Read
将真正返回List<T>
,那么通过调用ToList
,您将无需多少理由再次复制该列表。
IDbConnection.Query()
同样如此 - 也有buffered
参数,默认情况下为true,因此默认情况下也会返回List<T>
。
如果您更喜欢使用ToList()
,则可以将buffered: false
传递给Query()
或Read()
,以避免创建其他副本。
答案 1 :(得分:2)
此扩展程序是一个自定义dapper扩展程序,在调用ToList
之前会进行额外检查。 Source:
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);
直到现在这并没有真正受到伤害。现在新的List被初始化并填充,因为源不是列表而且不能被转换。所以效率低下。但如果逻辑也依赖于列表是相同的引用,这将不再起作用。
if(userList == seq)
{
// do something
}
使用数组后始终为false
。所以代码被默默地打破了。
简而言之:我不喜欢AsList
方法。您可以随时自行检查类型。