Tristan Trainer
Tristan Trainer

Reputation: 3080

Is it possible to await a valid return from a Collection of Tasks?

I'm looking to use an array of Tasks to find a solution to a problem using multiple methods. The idea being that I use a different Task for each method. Is there a way to do a Tasks.WaitFirst(task => task.Result == true)? Any solutions I've found so far have been very messy, I'm thinking of scrapping the idea but want to check I'm not missing something!

Thanks!

Upvotes: 0

Views: 80

Answers (2)

Enigmativity
Enigmativity

Reputation: 117174

You should use Microsoft's Reactive Framework (aka Rx) - NuGet System.Reactive and add using System.Reactive.Linq; - then you can do this:

void Main()
{
    var query =
        from n in Observable.Range(0, 25)
        from v in Observable.FromAsync(() => GetValueAsync())
        select v;

    query.Take(1).Subscribe(x => Console.WriteLine(x));
}

private Random _random = new Random();

public async Task<int> GetValueAsync()
{
    var value = _random.Next(5, 100);
    Console.WriteLine($"!{value}");
    await Task.Delay(TimeSpan.FromSeconds(value));
    return value;
}

You basically end up with a simple query that you can use .Take(1) to get the first value to finish. It's nice a clean and simple.

If you post how you are creating the tasks then I can post a complete answer.

Upvotes: 2

Ackdari
Ackdari

Reputation: 3508

I don't think this is something that this is in .net, but you can write your own version. Somethin like this

public static async Task<T> WhenFirst<T>(IEnumerable<Task<T>> tasks, Func<T, bool> predicate)
{
    var taskArray = tasks.ToArray();
    var completedTask = await Task.WhenAny(taskArray);

    if (predicate(await completedTask))
    {
        return await completedTask;
    }
    else
    {
        var notCompletedTasks = new List<Task<T>>();

        foreach(var task in taskArray)
        {
            if (task.IsCompleted && predicate(await task)) return await task;
            else notCompletedTasks.Add(task);
        }

        return await WhenFirst(notCompletedTasks, predicate);
    }
}

Upvotes: 0

Related Questions