异步函数中的TaskCompletionSource

时间:2016-02-02 16:20:47

标签: c# .net

我有这样一个功能:

public async Task<bool> DoSomething()
{
   var tcs = new TaskCompletionSource<bool>();

   // Here is the problem. I need to keep this line because I wait on something asynchronously, but the function must return bool and I can't just return tcs.Task
   while(something)
      await Task.Delay(100);

   someobject.somevent += () => {
      // do some sht
      tcs.SetResult(true);
   }

   // it doesn't work
   return tcs.Task;
}

它只是一个假代码,但我有真实的情况,我需要这个。我想保持DoSomething异步,但我也希望将Task.Delay / Sleep保留在其中。如何在非同步函数中返回任务?

更新:

这项工作:

class Program
    {
        static TaskCompletionSource<bool> tcs = new TaskCompletionSource<bool>();


        static Task<bool> Test()
        {
           // tcs = new TaskCompletionSource<bool>();
            Task.Factory.StartNew(() =>
            {
                Console.WriteLine("Waiting...");
                Thread.Sleep(5000);
                Console.WriteLine("Setting result");
                if(tcs.TrySetResult(true))
                    Console.WriteLine("Result has been set");


            });

            return tcs.Task;
        }

        static async Task Test2()
        {
            Console.WriteLine("Starting awaiting");
            var result = await Test();
            Console.WriteLine(result.ToString());
        }

        static void Main(string[] args)
        {


            Test2();

            Console.ReadKey(false);

        }
    }

这并不是

static async Task<bool> Test()
{
   // tcs = new TaskCompletionSource<bool>();
    Task.Factory.StartNew(() =>
    {
        Console.WriteLine("Waiting...");
        Thread.Sleep(5000);
        Console.WriteLine("Setting result");
        if(tcs.TrySetResult(true))
            Console.WriteLine("Result has been set");


    });


    return await tcs.Task;
}

更糟糕的是,我在我的Windows窗体应用程序中测试了它并等待tcs.Task导致来自System.Threading的奇怪崩溃...... dll

2 个答案:

答案 0 :(得分:7)

如果我理解正确(这很棘手,因为你的问题不容易理解),你可以按如下方式重述:

public async Task<bool> DoSomething()
{
   var tcs = new TaskCompletionSource<bool>();
   someobject.somevent += () => {
      // do some sht
      tcs.SetResult(true);
   }

   return await tcs.Task;
}

答案 1 :(得分:7)

如果你将事件触发转化为Task成为自己的方法,那么整个事情会更加优雅。

public static Task<bool> WhenSomeEvent(this SomeObject someobject)
{
    var tcs = new TaskCompletionSource<bool>();
    Action handler = null;
    handler = () =>
    {
        tcs.SetResult(true);
        someobject.SomeEvent -= handler;
    };
    someobject.SomeEvent += handler;
    return tcs.Task;
}

这允许您单独编写业务逻辑,而不会混淆将事件转换为Task的所有逻辑:

public async Task<bool> DoSomething()
{
    while(something)
        await Task.Delay(100);

    return await someobject.WhenSomeEvent();
}