0

I have a non Async method that needs to wait on the results of another method. That method itself builds an array of tasks, and waits on all of them, then returns a boolean result. I had to make the task that was called Async, and now I cannot get a simple boolean back out of it. When you read the code below, it all compiles except for the "StartNew ProcessDbList" line, it says it cannot convert a Task<bool> to a bool. How do I arrange this so that I get a simple boolean back that the ProcessInbox method can return?

    public bool ProcessInbox(List<SessionContext> sessionContextList, FsFcsService curSvc)
    {
        bool resultBool = false;

        List<SessionContext> tempSessionList = sessionContextList.ToList();

        //below is the line that will not compile with the type conversion error
        Task<bool> theTask = Task<bool>.Factory.StartNew(() => ProcessDbList(tempSessionList, curSvc));
        resultBool = theTask.Result;
        return resultBool;
    }

    public async  Task<bool> ProcessDbList(List<SessionContext> sessionList, FsFcsService curSvc) 
    {

        bool resultBool = false;

        IEnumerable<Task<bool>> TasksList =
            from SessionContext session in sessionList select ProcessDb(session, curSvc);

        Task<bool>[] TaskArray = TasksList.ToArray();

        // Await the completion of all the running tasks.
        // this line is what forces the method to be Async and return a Task<bool> 
        bool[] resultsArr = await Task.WhenAll(TaskArray);

        foreach (bool indivResult in resultsArr)
        {
            if (indivResult)
            {
                // if any result is true, this method returns true
                resultBool = true;
                break;
            }
        }
        // this is where I should probably be returning something other than a simple bool
        return resultBool;
    }
dac
  • 57
  • 7

3 Answers3

2

I have a non Async method that needs to wait on the results of another method.

The ideal answer is to make the calling method async:

public async Task<bool> ProcessInboxAsync(List<SessionContext> sessionContextList, FsFcsService curSvc)
{
  bool resultBool = false;
  List<SessionContext> tempSessionList = sessionContextList.ToList();
  return await ProcessDbList(tempSessionList, curSvc);
}

The method is, after all, doing asynchronous work, and therefore it should be asynchronous. There are various hacks to try to force asynchronous work done synchronously, but none of them work in all scenarios. The best solution is to have the asynchronous work naturally represented by asynchronous methods.

P.S. If you want to run CPU-bound work on a background thread, use Task.Run; StartNew is dangerous and should be avoided. However, in this case, there's no need for a background thread at all.

Stephen Cleary
  • 437,863
  • 77
  • 675
  • 810
  • Sadly, this is an existing project, and I don't have the freedom to make the methods Async "all the way up." So, at some point, I have to have a synchronous method calling an Async method, and this is the most logical place to do it. I found this answer (from you), and I'm assuming I can apply the same logic here? http://stackoverflow.com/questions/9343594/how-to-call-asynchronous-method-from-synchronous-method-in-c – dac Dec 18 '14 at 13:53
  • @dac: Yes, but please be aware (as I mentioned in my answer) that these are all hacks and none of them work in every scenario. There is no "one answer" to this problem (other than "make it async all the way"). – Stephen Cleary Dec 18 '14 at 14:23
1

I'm assuming 'ProcessDB' is an async method here, in which case you shoudn't need to concern yourself with wrapping the result up in yet another task here:

Task<bool> theTask = Task<bool>.Factory.StartNew(() => ProcessDbList(tempSessionList, curSvc));

and instead just use the returned task directly, since you're going to block for the result anyway when you use the Result property.

Try:

Task<bool> theTask = ProcessDbList(tempSessionList, curSvc);
Adam Rhodes
  • 199
  • 6
0

Adam Rhodes already said you don't need to wrap it in a task, you can also use .Result when calling an async method from a synchronous method.

public bool ProcessInbox(List<SessionContext> sessionContextList, FsFcsService curSvc)
{
    return ProcessDbList(sessionContextList.ToList(), curSvc).Result;
}
fotijr
  • 946
  • 11
  • 20