【问题标题】:Type conversion error with async programming异步编程的类型转换错误
【发布时间】:2014-01-06 13:20:17
【问题描述】:

谁能告诉我为什么这不起作用?

我有一个看起来像这样的方法:

public virtual async Task<IList<User>> GetAll()
{
    return this.db.Users.Where(model => model.CompanyId.Equals(this.companyId, StringComparison.OrdinalIgnoreCase)).ToListAsync();
}

当我尝试编译我的代码时,我收到一条错误消息:

错误 10 无法将类型“System.Threading.Tasks.Task>”隐式转换为“System.Collections.Generic.IList”。存在显式转换(您是否缺少演员表?) C:\Users\Jaymie\Documents\GitHub\Skipstone\Skipstone.Web\Repositories\UserRepository.cs 70 20 Skipstone.Web

但直接在它下面我有这个方法:

public Task<User> FindByIdAsync(string userId)
{
    return this.db.Users.Where(model => model.Id.Equals(userId, StringComparison.OrdinalIgnoreCase)).SingleOrDefaultAsync();
}

效果很好。

我想我只见树木不见森林,所以需要别人的眼睛来帮助我:)

【问题讨论】:

    标签: c# entity-framework asynchronous


    【解决方案1】:

    ToListAsync 方法返回一个 Task&lt;List&lt;T&gt;&gt; 对象,在您的情况下它转换为一个 Task&lt;List&lt;User&gt;&gt; 对象,但您的方法的返回类型是 Task&lt;IList&lt;User&gt;&gt;

    这里的问题是 TTask&lt;T&gt; 中不支持协方差。

    所以,要么将方法的返回类型更改为Task&lt;List&lt;User&gt;&gt;,要么自己编写代码进行转换:

    return this.db.Users
        .Where(model => model.Id.Equals(userId, StringComparison.OrdinalIgnoreCase))
        .ToListAsync()
        .ContinueWith<IList<User>>(t => t.Result, TaskContinuationOptions.ExecuteSynchronously);
    

    【讨论】:

    • 啊,我明白了:)我认为这很简单:D
    • @r3plica:我在延续中添加了ExecuteSynchronously 参数,以减少延续任务的开销。
    • @JeanHominal 你能解释一下你添加 ExecuteSynchronously 的原因吗?我是整个同步/异步编程的新手,并试图理解它。在我看来,您所做的是将异步方法转换为同步方法,这似乎很奇怪。即使你获得了性能,你也失去了异步性。
    • @MikeDymond:不,我没有将异步方法变成同步方法。这里发生了两个操作:首先,创建列表,其次,从原始Task&lt;List&lt;User&gt;&gt; 对象中解包列表。 ExecuteSynchronously 所做的是指定第二个任务相对于第一个任务同步执行 - 如果第一个任务异步执行,那么整个过程仍然异步运行。有关详细信息,请参阅documentation
    • @JeanHominal 谢谢你,这真的很有帮助。希望我可以发表评论:-)
    【解决方案2】:

    如果你使用 async 关键字,那么你需要使用 await 关键字返回原始类型。

    public virtual async Task<IList<User>> GetAll()
    {
        return await this.db.Users.Where(model =>
             model.CompanyId.Equals(this.companyId, 
                  StringComparison.OrdinalIgnoreCase)).ToListAsync().ConfigureAwait(false);;
    }
    

    或者如果没有异步,您需要像在第二个工作示例中那样指定类型 Task。

    【讨论】:

    • 您的代码无法编译。正如MSDN 中所述,“异步方法的返回类型可以是Task&lt;TResult&gt;Taskvoid”。
    • 好的,谢谢。我错过了。没错,它应该有 Task 作为结果类型。
    • @ScottChamberlain:实际上,asyncawait 用于将任务结果从List&lt;User&gt; 向上转换为IList&lt;User&gt;
    • @SergeyLitvinov:此外,您应该使用ConfigureAwait(false) 跟进您对ToListAsync() 的呼叫——原因是,在Task 对象上使用await 时,您应该如果您不关心方法的其余部分如何同步,请始终使用ConfigureAwait(false)。 (原因在Stephen Cleary's blog post有解释。)
    • 感谢@JeanHominal 的评论,我不知道。非常有趣的博文!
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-11-27
    • 2017-04-10
    • 2015-12-23
    • 1970-01-01
    相关资源
    最近更新 更多