Как преобразовать синхронный метод в асинхронный без изменения его подписи - PullRequest
0 голосов
/ 07 января 2019

У меня есть крупномасштабное решение C # с 40-ю модулями.

Я пытаюсь преобразовать службу, используемую в рамках решения, из синхронной в асинхронную.

проблема в том, что я не могу найти способ сделать это без изменения сигнатуры метода.

Я пытался обернуть указанную асинхронную требуемую операцию в Task, но для этого нужно изменить сигнатуру метода.

Я пытался изменить вызывающую сторону, чтобы она сама блокировалась во время работы метода, но это очень хорошо испортило мою систему, потому что это очень длинная цепочка вызовов, и изменение каждого члена в цепочке для блокировки само по себе является серьезной проблемой.

public SomeClass Foo()
{
// Synchronous Code
}

Преврати это в:

public SomeClass Foo()
{
//Asynchronous code
}

в то время как все абоненты остаются прежними

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

Ответы [ 3 ]

0 голосов
/ 07 января 2019

Если вам отчаянно нужно это сделать, этого можно достичь, заключив код Synchronous, который должен стать Asynchronous в Task, это можно сделать так:

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
}

Код, который вы пишете внутри Task.Run(() => ...), будет выполняться асинхронно

Краткое объяснение: с Task t = Task.Run(() => ...) мы начинаем новый Task, «странный» параметр - это лямбда-выражение, в основном мы передаем анонимный метод в метод Run, который будет быть казненным Task
Затем мы ждем окончания задачи с t.Wait();. Метод Wait может возвращать значение, вы можете вернуть значение из анонимного метода, как и из любого метода, с ключевым словом return

Примечание: Это может, но не должно быть сделано. Смотрите ответ Шона для более

0 голосов
/ 07 января 2019

Любая реализация, которая в корне меняет что-то от синхронизации к асинхронности, будет включать изменение подписи. Любой другой подход просто не будет работать хорошо. Принципиально: асинхронизация и синхронизация требуют разных API, что означает: разные подписи. Это неизбежно, и, честно говоря, «Как преобразовать синхронный метод в асинхронный без изменения его сигнатуры?» это неразрешимая проблема (и, скорее всего, неправильный вопрос). Извините, если мне кажется, что я не отвечаю на вопрос, но ... иногда ответ таков: «Вы не можете, и любой, кто говорит, что может, соблазняет вас по очень плохому пути».


В смысле async / Task<T> наиболее распространенный способ сделать это без нарушения совместимости - это добавить новый / отдельный метод, чтобы вы получили

SomeReturnType Foo();

и

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

ничего такого, что Foo и FooAsync здесь, вероятно, имеют похожих, но разных реализаций - одну, предназначенную для использования асинхронной, другую, которая работает чисто синхронно. не хорошая идея подделать одну, вызвав другую - и «синхронизировать по асинхронному» (синхронная версия, вызывающая асинхронную версию), и «асинхронно по синхронизированному» (асинхронная версия, вызывающая синхронизирующую версию) являются анти-паттернами, и их следует избегать (первое гораздо вреднее второго).


Если вы действительно не хотите этого делать, вы также можете сделать что-то вроде добавления FooCompleted события обратного вызова (или аналогичного), но: это по-прежнему принципиально изменение подписи, и вызывающему абоненту все равно придется использовать API по-другому. К тому времени, как вы это сделали - вы могли бы также упростить для потребителя добавление вместо него Task<T> API.

0 голосов
/ 07 января 2019

Обычный шаблон - добавить Async к имени метода и обернуть возвращаемый тип в Task. Итак:

public SomeClass Foo()
{
// Synchronous Code
}

становится:

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

В итоге вы получите две версии метода, но он позволит вам постепенно перенести ваш код на асинхронный подход и не нарушит существующий код во время выполнения миграции.

...