Return Task<IReadOnlyCollection<T>> 从 EF Core 查询而不等待?
Return Task<IReadOnlyCollection<T>> from EF Core query without await?
我希望我的类型尽可能具体。在提供封装查询的方法时,通常会看到 List<T>
returned(或更具体地说 Task<List<T>>
。)难怪 EF Core 的 .ToListAsync()
方法。但这不是很准确,是吗? List<T>
是 SQL 服务器(或您正在使用的任何持久性)中更大集合的投影。不可修改。
我想从我的方法中 return IReadOnlyCollection<T>
。这似乎更准确。我正在 return 从我的源数据中投影,您不能通过修改投影来修改源数据。我的结果也不会被错误地修改而不回退到 List<T>
,在这一点上你已经走得太远了我假设你知道你在做什么。
所以我尝试像同步一样return界面。
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>>
。当然,您可以尝试显式强制转换,但出于同样的原因,编译器也不喜欢那样。
嗯,这很烦人。但是我们可以很容易地用 async wait
剥离 Task<T>
。
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 为 "free" return Task<IReadOnlyCollection<T>>
?
不知道 ToListAsync()
的作用,但按名称进行操作,如果我猜对了,它会迭代结果并将它们转换为后台线程上的列表和 returns 任务在生成列表之前必须 awaited
。
如果是这样,你的问题是
how to convert Task<List<T>>
to 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>
允许反方差,所以 Task<TChild>
(其中 Child : Parent)不能自动转换为 Task<TParent>
所以你需要这样做你自己。
我希望我的类型尽可能具体。在提供封装查询的方法时,通常会看到 List<T>
returned(或更具体地说 Task<List<T>>
。)难怪 EF Core 的 .ToListAsync()
方法。但这不是很准确,是吗? List<T>
是 SQL 服务器(或您正在使用的任何持久性)中更大集合的投影。不可修改。
我想从我的方法中 return IReadOnlyCollection<T>
。这似乎更准确。我正在 return 从我的源数据中投影,您不能通过修改投影来修改源数据。我的结果也不会被错误地修改而不回退到 List<T>
,在这一点上你已经走得太远了我假设你知道你在做什么。
所以我尝试像同步一样return界面。
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>>
。当然,您可以尝试显式强制转换,但出于同样的原因,编译器也不喜欢那样。
嗯,这很烦人。但是我们可以很容易地用 async wait
剥离 Task<T>
。
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 为 "free" return Task<IReadOnlyCollection<T>>
?
不知道 ToListAsync()
的作用,但按名称进行操作,如果我猜对了,它会迭代结果并将它们转换为后台线程上的列表和 returns 任务在生成列表之前必须 awaited
。
如果是这样,你的问题是
how to convert
Task<List<T>>
toTask<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>
允许反方差,所以 Task<TChild>
(其中 Child : Parent)不能自动转换为 Task<TParent>
所以你需要这样做你自己。