Любая реализация, которая в корне меняет что-то от синхронизации к асинхронности, будет включать изменение подписи. Любой другой подход просто не будет работать хорошо. Принципиально: асинхронизация и синхронизация требуют разных API, что означает: разные подписи. Это неизбежно, и, честно говоря, «Как преобразовать синхронный метод в асинхронный без изменения его сигнатуры?» это неразрешимая проблема (и, скорее всего, неправильный вопрос). Извините, если мне кажется, что я не отвечаю на вопрос, но ... иногда ответ таков: «Вы не можете, и любой, кто говорит, что может, соблазняет вас по очень плохому пути».
В смысле async
/ Task<T>
наиболее распространенный способ сделать это без нарушения совместимости - это добавить новый / отдельный метод, чтобы вы получили
SomeReturnType Foo();
и
Task<SomeReturnType> FooAsync(); // or ValueTask<T> if often actually synchoronous
ничего такого, что Foo
и FooAsync
здесь, вероятно, имеют похожих, но разных реализаций - одну, предназначенную для использования асинхронной, другую, которая работает чисто синхронно. не хорошая идея подделать одну, вызвав другую - и «синхронизировать по асинхронному» (синхронная версия, вызывающая асинхронную версию), и «асинхронно по синхронизированному» (асинхронная версия, вызывающая синхронизирующую версию) являются анти-паттернами, и их следует избегать (первое гораздо вреднее второго).
Если вы действительно не хотите этого делать, вы также можете сделать что-то вроде добавления FooCompleted
события обратного вызова (или аналогичного), но: это по-прежнему принципиально изменение подписи, и вызывающему абоненту все равно придется использовать API по-другому. К тому времени, как вы это сделали - вы могли бы также упростить для потребителя добавление вместо него Task<T>
API.