【问题标题】:How to await multiple possibly uninitialized Tasks in C#?如何在 C# 中等待多个可能未初始化的任务?
【发布时间】:2021-01-03 18:03:51
【问题描述】:

我有一个创建资源的 API POST 端点,该资源可能有多个关系。为了确保首先使用有效关系创建资源,我需要检查给定的 ID 是否存在。有多种这样的关系,我不想按顺序等待每一个。这是我的代码:

[HttpPost]
public async Task<ActionResult<Person>> PostPerson(Person person)
{
    ValueTask<Person> master, apprentice;
    ValueTask<Planet> planet;
    ValueTask<Models.LifeFormType> lifeFormType;
    if (person.MasterId.HasValue)
    {
        master = _context.People.FindAsync(person.MasterId);
    }
    

    if (person.ApprenticeId.HasValue)
    {
        apprentice = _context.People.FindAsync(person.ApprenticeId);
    }

    if (person.FromPlanetId.HasValue)
    {
        planet = _context.Planets.FindAsync(person.FromPlanetId);
    }

    if (person.LFTypeId.HasValue)
    {
        lifeFormType = _context.LifeFormTypes.FindAsync(person.LFTypeId);
    }
    List<ValueTask> tasks = new List<ValueTask> {master, apprentice, planet, lifeFormType};

    // if the above worked I'd process the tasks as they completed and throw errors
    // if the given id was not found and such
    
    _context.Attach(person);
    // _context.People.Add(person);
    await _context.SaveChangesAsync();

    return CreatedAtAction("GetPerson", new { id = person.Id }, person);
}

如图here 所示,我想等待[master,apprentice,planet,lifeFormType] 的列表完成,但在创建Local variable 'master' might not be initialized before accessing 的列表期间出现错误。因此,我尝试在每次检查资源是否具有该值来创建 else 块并以某种方式添加 ValueTask.CompletedTask ,如下所示:

if (person.MasterId.HasValue)
{
    master = _context.People.FindAsync(person.MasterId);
}
else
{
    master = ValueTask.CompletedTask;
}

然后我收到一条错误消息,提示 Cannot convert source type 'System.Threading.Tasks.ValueTask' to target type 'System.Threading.Tasks.ValueTask&lt;Models.Person&gt;'

如何做到这一点?我想我现在只是等待每个请求。

【问题讨论】:

  • ValueTask&lt;Person&gt; master = default;

标签: c# async-await task


【解决方案1】:

您可以通过在声明站点初始化master 来避免这种情况。

最简单的方法是使用default 关键字。

ValueTask<Person> master = default;

【讨论】:

  • 这解决了第一个错误,但是如何将ValueTask&lt;Person&gt;ValueTask&lt;Planet&gt; 粘贴到一个列表中,因为我得到Argument type 'System.Threading.Tasks.ValueTask&lt;Models.Person&gt;' is not assignable to parameter type 'System.Threading.Tasks.ValueTask'var tasks = new List&lt;ValueTask&gt; {master, apprentice, planet, lifeFormType};
  • @koral 我明白了。 ValueTask 表示不产生结果的异步操作。这与产生T 类型结果的ValueTask&lt;T&gt; 形成对比。 List&lt;ValueTask&lt;LeastCommonType&gt;&gt; 之类的东西是你想要的,但你可能想要重构一下。
  • await Task.WhenAll(master.AsTask(), apprentice.AsTask(), planet.AsTask(), lifeFormType.AsTask()); 这终于奏效了。
猜你喜欢
  • 1970-01-01
  • 2017-11-12
  • 2016-07-27
  • 1970-01-01
  • 1970-01-01
  • 2016-02-17
  • 2017-07-08
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多