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.
source to share
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() {}
}
source to share