-1

I need help understanding how Task work in c#. I want to call ExecuteClause once for every clause in clauses. I've figured out that I should create a list of tasks and then

await Task.WhenAll(taskList);

Finally I can get the result of each task. This is what I have so far:

public async Task Execute(string[] clauses)
{
    var taskList = new List<Task<in>>();

    // Here I want to call ExecuteClause for each string in clauses
    // and wait for the result.
}

private async Task<int> ExecuteClause(string clause)
{
    var connectionString = ConfigurationManager.ConnectionStrings["default"].ConnectionString;
    var connection = new SqlConnection(connectionString);
    await connection.OpenAsync();

    var r = await new SqlCommand(clause, connection).ExecuteReaderAsync();

    while (await r.ReadAsync())
    {
        ...
    }

    r.Close();

    connection.Close();

    // Just an example returning an int
    return 1;
}
Asken
  • 7,679
  • 10
  • 45
  • 77
  • 3
    `var taskList = clauses.Select(c => ExecuteClause(c));` or jus tuse a simple `for` loop. – DavidG Feb 09 '18 at 15:19
  • @DavidG Brilliant! I think I finally understand how it works now. Much easier than I thought! – Asken Feb 09 '18 at 15:21
  • @DavidG - you can also use ExecuteClause as a method group for the call to Select – Josh E Feb 09 '18 at 15:26
  • 1
    @JoshE Yes and that's how I would probably write it in code, but for SO purposes it often confuses people. – DavidG Feb 09 '18 at 15:26

1 Answers1

0

I think the answer is simpler than you suspected.

You'll loop over the clauses array and add a new Task to the taskList in each iteration. Afterwards, you'll use WhenAll to aggregate all of the separate tasks into a single one that returns when all constituent tasks have finished:

public async Task Execute(string[] clauses)
{
    var taskList = clauses.Select(ExecuteClause);
    return Task.WhenAll(taskList);
}

You'll want to fix your ExecuteClause method to ensure proper disposal, since the way it's currently written may not handle the connections in all situations:

private async Task<int> ExecuteClause(string clause)
{
    var connectionString = ConfigurationManager
                 .ConnectionStrings["default"].ConnectionString;
    using (var connection = new SqlConnection(connectionString)) {

        await connection.OpenAsync();

        var r = await new SqlCommand(clause, connection).ExecuteReaderAsync();

        while (await r.ReadAsync())
        {
            ...
        }

        r.Close();

        connection.Close();
    }
    // Just an example returning an int
    return 1;
}
Josh E
  • 7,390
  • 2
  • 32
  • 44