3

I can solve this in .Net 4.5 but I must solve it in .Net 4.0, and so far i have not been successful. I have not been able to get my replies into a Task<List<MyDataObject>>. The code below can create List<MyDataObject>.

public Task<List<MyDataObject>> Foo()
{
     IEnumerable<string> names = GetList();
     var tasks = new List<Task>();
     foreach (var name in names)
     {               tasks.Add(Task<MyDataObject>.Factory.StartNew(
               () =>
               {
                    var reply = new MyDataObject();
                    var workerObject = new WorkerObject();
                    workerObject.Foo2();
                    reply.Success = true;
                    return reply;
                }));
       }

       Task.WaitAll(tasks.ToArray());
       var replyList = new List<MyDataObject>();
       for (int i = 0; i < tasks.Count(); i++)
       {     replyList.Add(((Task<MyDataObject>)tasks[i]).Result);
        }

        return replyList;
}

WhenAll() is 4.5 only

await is 4.5 only

so i cannot accept those

I agree that this doesnt compile. What I showed was i can iterate through the results. However I do not know how to go from

List<MyDataObject>()

to

Task<List<MyDataObject>>

Thank you for the replies. I am going to accept Yuval Itzchakov's answer because it solves my problem in a simple manner. I am limited to no new assemblies for this use case. I would have selected 280Z28's second option had I had another method that required this functionality.

KCIsLearning
  • 289
  • 1
  • 6
  • 14
  • 1
    Your function should return a `Task>` yet you return a `List`. Without knowing about `Task`s, this looks like a compile-time issue to me. – Jashaszun Aug 04 '14 at 17:46
  • 1
    Also, what do you mean by `so far I have not been successful`? What isn't working? Please give us specifics. – Jashaszun Aug 04 '14 at 17:46
  • It would be better to use async/await. But without that option, try this: [Creating a completed task](http://stackoverflow.com/questions/4245968/create-a-completed-taskt) – Jason P Aug 04 '14 at 18:00
  • 2
    https://www.nuget.org/packages/Microsoft.Bcl.Async/ – SLaks Aug 04 '14 at 18:26

2 Answers2

2

Use a TaskCompletionSource<List<MyDataObject>>

Task.WaitAll(tasks.ToArray());

var replyList = new List<MyDataObject>();

for (int i = 0; i < tasks.Count(); i++)
{                
    replyList.Add(((Task<MyDataObject>)tasks[i]).Result);
}

var tcs = new TaskCompletionSource<List<MyDataObject>>();
tcs.SetResult(replyList);
return tcs.Task;

You can also download Microsoft.Bcl.Async to get the NET 4.5 effect in .NET 4.0

Yuval Itzchakov
  • 146,575
  • 32
  • 257
  • 321
  • Do note that to use Microsoft.Blc.Async in .NET 4.0, you will need to install KB2468871 (Update for the .NET Framework 4) – Andy Aug 06 '14 at 05:46
1

You'll get precisely the same behavior in .NET 4.0 if you follow these steps:

Define a WhenAll method

public static Task<TResult[]> WhenAll<TResult>(IEnumerable<Task<TResult>> tasks)
{
    TaskCompletionSource<TResult[]> taskCompletionSource = new TaskCompletionSource<TResult[]>();
    Action<Task<TResult>[]> continuationAction =
        completedTasks =>
        {
            List<TResult> results = new List<TResult>();
            List<Exception> exceptions = new List<Exception>();
            bool canceled = false;

            foreach (var completedTask in completedTasks)
            {
                switch (completedTask.Status)
                {
                case TaskStatus.RanToCompletion:
                    results.Add(completedTask.Result);
                    break;

                case TaskStatus.Canceled:
                    canceled = true;
                    break;

                case TaskStatus.Faulted:
                    exceptions.AddRange(completedTask.Exception.InnerExceptions);
                    break;

                default:
                    throw new InvalidOperationException("Unreachable");
                }
            }

            if (exceptions.Count > 0)
                taskCompletionSource.SetException(exceptions);
            else if (canceled)
                taskCompletionSource.SetCanceled();
            else
                taskCompletionSource.SetResult(results.ToArray());
        };
    Task.Factory.ContinueWhenAll(tasks.ToArray(), continuationAction);
    return taskCompletionSource.Task;
}

Use the Select method from the Rackspace Threading Library to return the expected results

public Task<List<MyDataObject>> Foo()
{
    IEnumerable<string> names = GetList();
    var tasks = new List<Task<MyDataObject>>();
    foreach (var name in names)
    {
        tasks.Add(Task<MyDataObject>.Factory.StartNew(
            () =>
            {
                var reply = new MyDataObject();
                var workerObject = new WorkerObject();
                workerObject.Foo2();
                reply.Success = true;
                return reply;

            }));
    }

    return WhenAll(tasks).Select(result => new List<MyDataObject>(result.Result));
}

Alternatively:

As an alternative, you could modify the WhenAll method above to return Task<List<TResult>> instead of Task<TResult[]>. This would allow you to simply use the following method.

public Task<List<MyDataObject>> Foo()
{
    IEnumerable<string> names = GetList();
    var tasks = new List<Task<MyDataObject>>();
    foreach (var name in names)
    {
        tasks.Add(Task<MyDataObject>.Factory.StartNew(
            () =>
            {
                var reply = new MyDataObject();
                var workerObject = new WorkerObject();
                workerObject.Foo2();
                reply.Success = true;
                return reply;

            }));
    }

    return WhenAll(tasks);
}
Sam Harwell
  • 97,721
  • 20
  • 209
  • 280