如何运行可能同步或可能异步的代码?

时间:2014-12-31 12:38:31

标签: c# asynchronous

我有一个带有一些异步方法的类,这些方法接受一个处理程序类,以决定在成功或失败时做什么。

public class FooModel
{
    private FooState fooState;

    public async Task UpdateFooAsync(IHandler handler)
    {
        try
        {
            var newFooState = await Something();
            fooState = newFooState;

            handler.Success();
        }
        catch
        {
            handler.Error();
        }
    }
}

public interface IHandler
{
    void Success();
    void Error();
}

我可以在我的代码中从几个不同的地方调用UpdateFooAsync。根据我从哪里调用它,我可能想做不同的事情。例如,一个同步示例:

public async void update_click(object sender, RoutedEventArgs e)
{
    await UpdateFooAsync(new Handler1());
}

public class Handler1 : IHandler
{
    public void Success()
    {
        Provider.Page.text = "hello";
    }
    public void Error() {}
}

但是我可能还想在以下之后进行异步操作:

private async void updateAndThenSomething_click(object sender, RoutedEventArgs e)
{
    await UpdateFooAsync(new Handler2());
}

// this will generate not implemented error obviously
public class Handler2 : IHandler
{
    public async void SuccessAsync()
    {
        await Provider.OperationAsync();
    }
    public void Error() {}
}

但是FooModel不知道我是否想要进行同步或异步操作。它不应该知道。有没有办法让handler.Success()运行同步代码或异步代码?我读了一些Stephen Toub的东西(link),这似乎意味着我不应该将Success变成一个任务,然后在UpdateFooAsync try块中等待该任务。

我想另一种选择是完全省去处理程序界面。但这需要大量的重构。上述情况在我的代码中发生了很多,通常不仅仅是成功和错误。我想强迫某人使用我的代码来指定成功,错误或其他什么。这就是我使用界面的原因。我想我也可以通过抛出不同的异常来做到这一点,但我也不确定这是个好主意。

1 个答案:

答案 0 :(得分:3)

您可以声明处理程序接口以返回Task,然后在同步情况下使用Task.FromResult返回。 E.g。

public interface IHandler
{
    Task Success();
    void Error();
}

public class Handler1 : IHandler
{
    public Task Success()
    {
        Provider.Page.text = "hello";
        return Task.FromResult<object>(null); 
    }
    public void Error() {}
}

public class Handler2 : IHandler
{
    public async Task Success()
    {
        return Provider.OperationAsync();
    }

    public void Error() {}
}