How do I run possibly synchronous or possibly asynchronous code?

I have a class with some asynchronous methods that take a handler class to decide what to do with success or failure.

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();
}

      

I could call UpdateFooAsync from several different places in my code. And depending on where I am calling it from, I might want to do different things. For example, a synchronous example:

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() {}
}

      

But I can also do an async operation after:

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() {}
}

      

But FooModel doesn't know if I want to do a sync or an async operation. And he didn't have to know. Is there a way to have a .Success () handler run either synchronous code or asynchronous code? I read some of Steven Toub's articles ( link ) which seems to imply that I shouldn't make Success a Task and then wait for that task in the UpdateFooAsync try block.

I guess the other option is to drop the handler interface entirely. But this will require a lot of refactoring. The above situation in the code is a lot, often with great success and error. I want to get someone to use my code to indicate what happens on success, error, or whatever. This is why I used the interface. I guess I could do it too by throwing different exceptions, but I'm not sure if this is a good idea.

+3


source to share


1 answer


You can declare your handler interface to return Task

, and then in the synchronous case, just return with Task.FromResult

. For example.



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() {}
}

      

+3


source







All Articles