我希望我的类型尽可能具体。提供封装查询的方法时,通常会看到返回List<T>
(或更具体地说是Task<List<T>>
。)EF Core的.ToListAsync()
方法也就不足为奇了。但这不是很准确吗? List<T>
是SQL Server(或您使用的任何持久性)中较大集合的投影。这是不可修改的。
我想从我的方法中返回IReadOnlyCollection<T>
。这似乎更准确。我正在从源数据返回一个投影,您不能通过修改投影来修改源数据。在不回退到List<T>
的情况下,也不能错误地修改我的结果,这时您已经走了很远,我假设您知道自己在做什么。
所以我试图像同步地那样只返回接口。
public Task<IReadOnlyCollection<TResult>> GetResultAsync() =>
_dbContext.Where(x => x.Property == true).ToListAsync();
我在这里避免使用async
和await
运算符。我想立即传递任务,以避免await
的开销。但是,当包装在Task<T>
中时,C#的类型系统无法识别包装的List<T>
可转换为IReadOnlyCollection<T>
。因此无法将Task<List<T>>
强制转换为Task<IReadOnlyCollection<T>>
。当然,您可以尝试进行显式强制转换,但是出于相同的原因,编译器也不愿意这样做。
那很烦人。但是我们可以很容易地用Task<T>
剥离async wait
。
public async Task<IReadOnlyCollection<TResult>> GetResultAsync() =>
await _dbContext.Where(x => x.Property = true).ToListAsync();
为了避免添加代码,我考虑了扩展方法。
public static async Task<IReadOnlyCollection<T>> ToReadOnlyCollectionAsync<T>(this IQueryable<T> query) =>
await query.ToListAsync();
这使await
脱离了我的方法,但是当然仍然要增加另一个等待时间。是否有一种方法可以从EF Core 2.1中免费退还Task<IReadOnlyCollection<T>>
?
答案 0 :(得分:1)
不知道ToListAsync()
会做什么,只是按名称进行,如果我猜对了,它将迭代结果并将其转换为后台线程上的列表,并返回必须为{{1 }}生成列表之前。
如果是这样,您的问题是
如何将
awaited
转换为Task<List<T>>
。
如果是这样,理论上您可以执行以下操作:
Task<IReadonlyCollection<T>>
我不相信 public Task<IReadOnlyCollection<string>> ToReadOnlyCollection()
{
return ToListAsync().ContinueWith(x => new ReadOnlyCollection<string>(x.Result) as IReadOnlyCollection<string>);
}
public Task<IReadOnlyList<string>> ToReadOnlyList()
{
// if you don't mind an IReadOnlyList, you can use this
// one which doesn't involve creating a new collection
return ToListAsync().ContinueWith(x => x.Result as IReadOnlyList<string>);
}
private Task<List<string>> ToListAsync()
{
return Task.Run(() =>
{
Task.Delay(1000);
return new List<string>
{
"1",
"2",
"3"
};
});
}
允许使用反方差,因此Task<T>
(其中,Child:Parent)不能自动转换为Task<TChild>
,因此您需要自己进行操作。