为什么这些任务会执行两次?

Fla*_*ter 0 c# async-await

我正在尝试将多个实体异步添加到我的数据库中,作为集成测试的“排列”部分。

但是,我的原始代码出现了双重条目:

private async Task<Foo[]> GenerateFoos(params string[] names)
{
    var tasks = names.Select(async name =>
    {
        var foo = new Foo() { Name = name };
        await AddAsync(foo);
        return foo;
    });

    await Task.WhenAll(tasks);

    return tasks.Select(task => task.Result).ToArray();
}

[Test]
public async Task MyTest()
{
    var expected = await GenerateFoos("A", "B", "C");
}
Run Code Online (Sandbox Code Playgroud)

它在我的数据库中生成两倍数量的对象(每个对象两个),我不知道为什么。

我在网上查找了其他示例,但它们都假设 async 方法(AddAsync在我的例子中)返回我想要返回的对象,但这里的情况并非如此;asAddAsync只返回 ID,但我想返回添加的对象本身。

我已经重新编写了两次代码,这两个替代方案不会插入重复项:

// Alternative 1
    
var result = new List<Corporation>();
        
foreach (var name in names)
{
    var foo= new Foo() { Name = name };
    await AddAsync(foo);
    result.Add(foo);
}

return result.ToArray();

// Alternative 2

var foos = names.Select(name => new Foo{ Name = name });

await Task.WhenAll(foos.Select(foo => AddAsync(foo)));

return foos.ToArray();
Run Code Online (Sandbox Code Playgroud)

所以我很确定错误源于我的代码,而不是AddAsync. 但我不明白为什么第一个表现不同。虽然我不期待AddAsync这里的内容,但我为了完成而添加它:

public static async Task AddAsync<TEntity>(TEntity entity)
    where TEntity : class
{
    using var scope = _scopeFactory.CreateScope();

    var context = scope.ServiceProvider.GetService<MyDbContext>();

    context.Add(entity);

    await context.SaveChangesAsync();
}
Run Code Online (Sandbox Code Playgroud)

谁能发现为什么我的任务被执行了两次?

GSe*_*erg 6

var tasks包含查询,而不是查询的结果

此查询被枚举两次, onTask.WhenAll()和 on tasks.Select()
因为调用AddAsync是在枚举期间创建的函数内部,所以它会被执行两次。

物化查询解决了这个问题:

var tasks = names.Select(async name =>
    {
        var foo = new Foo() { Name = name };
        await AddAsync(foo);
        return foo;
    })
    .ToList();
Run Code Online (Sandbox Code Playgroud)

请注意,您的备选方案 2 包含相同的双重枚举问题,但这次枚举只会导致Foo不必要地创建新实例。调用AddAsync在枚举之外。