首页 > 解决方案 > 组合 await 与 ContinueWith

问题描述

我遇到了以下我试图理解的异步代码(为本示例进行了简化):

class Program
{
    static async Task Main(string[] args)
    {
        var foo = new Foo();

        try
        {
            var bar = new Bar();
            await foo.ComputeNumber(bar.GetNumberAsync());
        }
        catch (Exception e)
        {
            Console.WriteLine($"Logged exception: {e}");
        }
        Console.WriteLine($"The number is {foo.Number}");
        Console.ReadKey();
    }
}

public class Foo
{
    public int Number { get; private set; } = 0;

    public async Task ComputeNumber(Task<int> inputTask)
    {
        await inputTask.ContinueWith(x => Number = x.Result);
    }
}

public class Bar
{
    public async Task<int> GetNumberAsync()
    {
        return await Task.Factory.StartNew(() =>
        {
            if (DateTime.Now.Date.DayOfWeek != DayOfWeek.Monday)
            {
                throw new Exception("This function works only on Mondays.");
            }
            return 17;
        });
    }
}

这段代码按我的预期工作(至少我希望如此),但我认为这个问题应该通过以下方式之一解决(我认为两者都是正确的)。类将Bar保持不变。

第一种(异步/等待)方法:

class Program
{
    static async Task Main(string[] args)
    {
        var foo = new Foo();

        try
        {
            var bar = new Bar();
            await foo.ComputeNumber(bar.GetNumberAsync());
        }
        catch (Exception e)
        {
            Console.WriteLine($"Logged exception: {e}");
        }
        Console.WriteLine($"The number is {foo.Number}");
        Console.ReadKey();
    }
}

public class Foo
{
    public int Number { get; private set; } = 0;

    public async Task ComputeNumber(Task<int> inputTask)
    {
        Number = await inputTask;
    }
}

第二种(基于任务的)方法:

class Program
{
    static void Main(string[] args)
    {
        var foo = new Foo();
        var bar = new Bar();
        foo.ComputeNumber(bar.GetNumberAsync());

        Console.WriteLine($"The number is {foo.Number}");
        Console.ReadKey();
    }
}

public class Foo
{
    public int Number { get; private set; } = 0;

    public void ComputeNumber(Task<int> inputTask)
    {
        inputTask.ContinueWith(x =>
        {
            if (x.IsFaulted)
            {
                Console.WriteLine($"Logged exception: {x.Exception}");
            }
            else
            {
                Number = x.Result;
            }
        });
    }
}

我很欣赏为什么使用异步代码的原始示例可以这样编写的每一个解释。

标签: c#async-awaittask-parallel-library

解决方案


您可以将其await视为替代大多数用途的语言功能,ContinueWith因此将两者混合似乎没有必要。

请注意,您的第二次重写与第一次不同,在两个方面。

  1. 它吞下错误而不是浮出水面。

  2. 它不返回 a Task,因此调用者将不知道何时将aNumber设置为最终结果。

ComputeNumber目的可疑(这可能是因为它被简化以在此处发布)。为什么不简单地await bar.GetNumberAsync()然后在后续语句中使用获得的值?的重点await是允许Task<T>被视为与T程序代码中的相同。


推荐阅读