How to convert synchronous method to asynchronous without changing it's signature

别等时光非礼了梦想. 提交于 2021-02-16 22:47:11

问题


I have a large scale C# solution with 40-ish modules.

I'm trying to convert a service used solution-wide from synchronous to asynchronous.

the problem is I can't find a way to do so without changing the signature of the method.

I've tried wrapping said asynchronous desired operation with Task but that requires changing the method signature.

I've tried changing the caller to block itself while the method is operating but that screwed my system pretty good because it's a very long calling-chain and changing each of the members in the chain to block itself is a serious issue.

public SomeClass Foo()
{
// Synchronous Code
}

Turn this into:

public SomeClass Foo()
{
//Asynchronous code
}

whilst all callers stay the same

public void DifferentModule()
{
 var class = Foo();
}

回答1:


Any implementation that fundamentally changes something from sync to async is going to involve a signature change. Any other approach is simply not going to work well. Fundamentally: async and sync demand different APIs, which means: different signatures. This is unavoidable, and frankly "How to convert synchronous method to asynchronous without changing it's signature?" is an unsolvable problem (and more probably: the wrong question). I'm sorry if it seems like I'm not answering the question there, but... sometimes the answer is "you can't, and anyone who says you can is tempting you down a very bad path".


In the async/Task<T> sense, the most common way to do this without breaking compatibility is to add a new / separate method, so you have

SomeReturnType Foo();

and

Task<SomeReturnType> FooAsync(); // or ValueTask<T> if often actually synchoronous

nothing that Foo and FooAsync here probably have similar but different implementations - one designed to exploit async, one that works purely synchronously. It is not a good idea to spoof one by calling the other - both "sync over async" (the synchronous version calling the async version) and "async over sync" (the async version calling the sync version) are anti-patterns, and should be avoided (the first is much more harmful than the second).


If you really don't want to do this, you could also do things like adding a FooCompleted callback event (or similar), but : this is still fundamentally a signature change, and the caller will still have to use the API differently. By the time you've done that - you might as well have made it easy for the consumer by adding the Task<T> API instead.




回答2:


The common pattern is to add an Async to the method name and wrap the return type in a Task. So:

public SomeClass Foo()
{
// Synchronous Code
}

becomes:

public Task<SomeClass> FooAsync()
{
// Asynchronous Code
}

You'll end up with two versions of the method, but it will allow you to gradually migrate your code over to the async approach, and it won't break the existing code whilst you're doing the migration.




回答3:


If you desperately need to do this, it can be achieved by wrapping the Synchronous code that needs to become Asynchronous in a Task this can be done like this:

public SomeClass Foo()
{
    Task t = Task.Run(() =>
    {
        // Do stuff, code in here will run asynchronously
    }

    t.Wait();
    // or if you need a return value: var result = t.Wait();
    return someClass;
    // or return result
}

Code you write inside the Task.Run(() => ...) will run asynchronously

Short explanation: with Task t = Task.Run(() => ...) we start a new Task, the "weird" parameter is a Lambda expression, basically we're passing a anonymous Method into the Run method which will get executed by the Task
We then wait for the task to finish with t.Wait();. The Wait method can return a value, you can return a value from an anonymous method just like from any method, with the return keyword

Note: This can, but should not be done. See Sean's answer for more



来源:https://stackoverflow.com/questions/54074060/how-to-convert-synchronous-method-to-asynchronous-without-changing-its-signatur

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!