Home > database >  Combine dual Sync/Async interface implementations
Combine dual Sync/Async interface implementations

Time:09-22

I have duplicate interface method(s) for Sync and Async versions. Each method is ~30 lines long and does exactly the same thing. Except in the middle where one awaits an Async method, but the other calls a Synchronous method.

My current pattern just combines them with a boolean I refer to as the "DoAsync" pattern, though I don't remember where I saw it some years ago.

Being that the implementation guarantees no async stuff is happening (No working with Tasks), does that change the understood logic of using GetAwaiter().GetResult() over .Result? Is it right to assume calling the private method synchronously would lose all accepted concerns of "calling async method synchronously" because of the style of implementation? What else changes? Or, what other patterns are common to combine async and sync methods that do exactly the same thing?

This is the pattern I'm talking about:

public class MyImplementation : IDoSomething {

    public async Task DoSomethingAsync(object input)
        => await DoSomethingInternally(input);

    public void DoSomething(object input)
        => DoSomethingInternally(input, false).GetAwaiter().GetResult();

    private async Task DoSomethingInternally(object input, bool runSynchronously = false) {
        //a dozen other lines of code
        object somethingINeed;
        if (runSynchronously) somethingINeed = GetSomething(input, lol);
        else somethingINeed = await GetSomethingAsync(input, lol);
        //a dozen other lines of code
    }
}

CodePudding user response:

C# methods are colored

Unfortunately C# doesn't have any abstractions for how a method is called. C# methods are colored and there's no getting around that.

One alternative is to only have an async implementation instead of both async and non-async. In your case you would throw away the public void DoSomething(object input) method (and move the body of the xyzInternally method to the async method).

Unfortunately that leads to an annoying condition where you have to use async/await all the way up the call stack from your async method. It's called "async cancer" and is caused by the fact that C# methods are colored.


I might be missing the big picture. If so, then please provide a couple more examples so I can see the same pattern that you're seeing.


P.S. Task.GetAwaiter().GetResult() is essentially the same as Task.Result. Yes there's a difference in how exceptions come through, but both can easily lead to deadlock (and other issues). For example: can you guarantee that await GetSomethingAsync(input, lol) will never reenter DoSomethingInternally?

CodePudding user response:

How about this:

public async Task DoSomethingAsync(object input)
{
    var lol = FirstDozenLinesWrapperMethod();
    await GetSomethingAsync(input, lol);
    LastDozenLinesWrapperMethod();
}

public void DoSomething(object input)
{
    var lol = FirstDozenLinesWrapperMethod();
    GetSomething(input, lol);
    LastDozenLinesWrapperMethod();
}
  • Related