C# 返回任务<;IReadOnlyCollection<;T>&燃气轮机;从EF核心查询不等待?

C# 返回任务<;IReadOnlyCollection<;T>&燃气轮机;从EF核心查询不等待?,c#,entity-framework-core,ef-core-2.1,C#,Entity Framework Core,Ef Core 2.1,我喜欢对我的类型尽可能具体。当提供封装查询的方法时,通常会看到返回的List(或者更具体地说是Task),这也难怪EF Core的.toListSync()方法。但这不是很准确,是吗列表是SQL Server(或您正在使用的任何持久性)中更大集合的投影。它是不可修改的 我想从我的方法返回IReadOnlyCollection。这似乎更准确。我正在从源数据返回投影,您不能通过修改投影来修改源数据。我的结果也不能被错误地修改,除非返回到列表,在这一点上,您已经走得够远了,我假设您知道自己在做什么 因

我喜欢对我的类型尽可能具体。当提供封装查询的方法时,通常会看到返回的
List
(或者更具体地说是
Task
),这也难怪EF Core的
.toListSync()
方法。但这不是很准确,是吗<代码>列表是SQL Server(或您正在使用的任何持久性)中更大集合的投影。它是不可修改的

我想从我的方法返回
IReadOnlyCollection
。这似乎更准确。我正在从源数据返回投影,您不能通过修改投影来修改源数据。我的结果也不能被错误地修改,除非返回到
列表
,在这一点上,您已经走得够远了,我假设您知道自己在做什么

因此,我尝试像同步返回一样返回接口

public Task<IReadOnlyCollection<TResult>> GetResultAsync() =>
  _dbContext.Where(x => x.Property == true).ToListAsync();
为了避免添加代码,我考虑了一种扩展方法

public static async Task<IReadOnlyCollection<T>> ToReadOnlyCollectionAsync<T>(this IQueryable<T> query) =>
  await query.ToListAsync();
publicstaticasync任务ToReadOnlyCollectionAsync(此IQueryable查询)=>
等待query.ToListAsync();

这从我的方法中获得了
await
,但当然仍然添加了另一个await。有没有一种方法可以从EF Core 2.1返回
Task
“免费”的任务?

不知道
ToListSync()
做什么,只知道名称,如果我猜对了,它会迭代结果并将其转换为后台线程上的列表,并返回在生成列表之前必须等待的任务

如果是这样的话,你的问题是

如何将
任务
转换为
任务

如果是这样,理论上你可以这样做:

    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"
            };
        });
    }
public任务ToReadOnlyCollection()
{
返回toListSync().ContinueWith(x=>newreadonlyCollection(x.Result)作为IReadOnlyCollection);
}
公共任务ToReadOnlyList()
{
//如果您不介意使用IReadOnlyList,可以使用
//不涉及创建新集合的集合
返回toListSync().ContinueWith(x=>x.Result作为IReadOnlyList);
}
私有任务ToListSync()
{
返回任务。运行(()=>
{
任务延迟(1000);
返回新列表
{
"1",
"2",
"3"
};
});
}

我不相信
任务
允许反向变化,因此
任务
(其中子项:父项)无法自动转换为
任务
,因此您需要自己完成

我将此标记为答案,但想快速回答您的问题
.ToListSync()
来自实体框架:查询SQL数据库,反序列化结果,并将投影作为包含所有反序列化对象的
列表返回。此外,我想指出
,因为这里的
可能是错误的运算符
正如
所示,结果可能不是
IReadOnlyCollection
类型,如果不是,则返回null即可。这是不正确的。如果
ToListAsync
的结果不是
IReadOnlyCollection
,那么我们应该
抛出
,因为出现了一些非常错误的情况,或者我们的底层框架已经更改,我们的代码需要更新。这里应该使用一个常规的旧类型转换来获得这种效果。@Licht感谢您纠正我关于
ToListAsync()
的错误。我已经很长时间没有使用
EF
了,我不记得曾经见过这种方法。关于
as
,我认为返回类型是
List
类型
List
实现
IReadOnlyList
,因此案例始终有效。
IReadOnlyCollection
也始终有效,因为我们首先创建一个
ReadOnlyCollection
新的ReadOnlyCollection(originalList
)然后“casting”它是一个
IReadOnlyCollection
。虽然打字速度很快,但这里或那里可能会有错误。这比实际(和完美)的实现更…意味着传达想法。我会忽略它,因为你提供的确切原因(想法比确切的实现更重要)然而,人们有从堆栈溢出复制粘贴的倾向。因此我认为实现尽可能正确是很重要的,因为我们在这里编写的代码可能会滑入我们甚至不知道的代码库。甚至可能是我们某天使用的代码库。
    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"
            };
        });
    }