Pregunta

I'm having a hard time understanding async and the corresponding behavior. This is a model of the program I'm trying to write, and a repro of the problem I'm having:

namespace AsyncTesting
{
    class Program
    {
        static void Main(string[] args)
        {
            Console.WriteLine("starting....");
            MyClass myClass = new MyClass();
            myClass.DoSomeWork();
            Console.WriteLine("ending....");
            Console.ReadLine();
        }
    }

    class MyClass
    {
        public bool DoSomeWork()
        {
            return GetTrue().Result;
        }

        Task<bool> GetTrue()
        {
            return new Task<bool>(() => true);
        }
    }
}

When I make the GetTrue().Result call, it never returns. My Task<bool> GetTrue() method is a dummy method for repro purposes, but I'm not quite sure why it never comes back. But it returns if I have this:

namespace AsyncTesting
{
    class Program
    {
        static void Main(string[] args)
        {
            Console.WriteLine("starting....");
            MyClass myClass = new MyClass();
            myClass.DoSomeWork();
            Console.WriteLine("ending....");
            Console.ReadLine();
        }
    }

    class MyClass
    {
        public async void DoSomeWork()
        {
            await GetTrue();
        }

        Task<bool> GetTrue()
        {
            return new Task<bool>(() => true);
        }
    }
}

The problem is, with my repro I want the initial behavior. I don't want async void for the calling method. I want to be able to return bool from my calling "normal" method. How can I achieve this? How can I get the first example to run and actually return the bool from DoSomeWork()?

Thank you in advance.

EDIT: Thank you for the answers. I think what the problem is, is that my GetTrue() method isn't a true repro. In my method, I'm not generating the actual Task<bool> object. It's really a call to Task.Factory.FromAsync<bool>() that is creating the Task<bool> object. And it's that task that I don't know how to "start". Any other ideas? Thanks!

¿Fue útil?

Solución

You're probably looking for:

Task<bool> GetTrue()
{
    return Task.FromResult(true);
}

instead of:

Task<bool> GetTrue()
{
    return new Task<bool>(() => true);
}

In the latter case, you don't even start the task you create. You'd need to start it with Task.Run or Task.RunSynchronously. Usually you don't create tasks directly via new Task(). Check Stephen Toub's "Task.Factory.StartNew" vs "new Task(...).Start" and "Task.Run vs Task.Factory.StartNew".

Depending on what you're trying to achieve, you might be tempted to do this:

Task<bool> GetTrue()
{
    return Task.Run(() => true);
}

However, usually this turns to be a known-anti-pattern, check "Should I expose asynchronous wrappers for synchronous methods?".

Updated to address the comments:

... the context is a WCF service. The Task.Factory.FromAsync() call is wrapping the Begin...() and End...() functions that the service has pushed to the consumer. But I see no way to actually start the task and it just hangs. ... it is the client-side making the WCF call. The client-side app is a Windows Phone 8 application.

You're experiencing a deadlock on the UI thread, because you're blocking on the result of a pending task (with task.Result). The task itself cannot be completed, because the await continuation is posted asynchronously to the dispatcher loop of the UI thread of your WP8 app, which is now blocked. Stephen Cleary explains this in great details in his blog. To avoid this, you should embrace "async all the way down" programming model. It practically means that you should make your UI event and command handlers async as well, and do var result = await task, rather than var result = task.Result in there.

Otros consejos

You need to start a task before it does anything.. calling Run will do that for you:

Task<bool> GetTrue()
{
    return Task.Run(() => true);
}

This gives the output you expect. Result is a blocking call. If your Task instance never starts.. Result can never return.

Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top