1
votes

Comment convertir une méthode synchrone en méthode asynchrone sans changer sa signature

J'ai une solution C # à grande échelle avec des modules 40-ish.

J'essaie de convertir un service utilisé à l'échelle de la solution de synchrone à asynchrone.

le problème est que je ne peux pas trouver un moyen de le faire sans changer la signature de la méthode. p>

J'ai essayé d'encapsuler ladite opération asynchrone souhaitée avec Task mais cela nécessite de changer la signature de la méthode.

J'ai essayé de changer l'appelant pour qu'il se bloque pendant que la méthode fonctionne mais cela a vissé mon système plutôt bon car c'est une très longue chaîne d'appels et changer chacun des membres de la chaîne pour se bloquer est un problème sérieux.

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

Transformez ceci en: p >

public SomeClass Foo()
{
//Asynchronous code
}

pendant que tous les appelants restent les mêmes

public SomeClass Foo()
{
// Synchronous Code
}


1 commentaires

Vous devez modifier la signature car vous les appelez également d’une manière différente. Sinon, il ne s'agirait pas de méthodes asynchrones.


3 Réponses :


2
votes

Le modèle courant consiste à ajouter un Async au nom de la méthode et à envelopper le type de retour dans une Task . Donc:

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

devient:

public SomeClass Foo()
{
// Synchronous Code
}

Vous vous retrouverez avec deux versions de la méthode, mais cela vous permettra de migrer progressivement votre code à l'approche asynchrone, et il ne cassera pas le code existant pendant que vous effectuez la migration.


3 commentaires

Bien que rappelez-vous, les appels Async doivent être effectués jusqu'au point d'entrée, c'est le moyen fiable de bénéficier du code Async


@orenk - Vous devrez changer le code, puisque vous changez le type de retour


Ouais, mais cela peut aussi être résolu sans avoir à changer toute la pile d'appels (au moins afaik)



0
votes

Si vous avez désespérément besoin de le faire, cela peut être réalisé en enveloppant le code Synchrone qui doit devenir Asynchrone dans une Tâche ceci peut être fait comme ceci:

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
}

Le code que vous écrivez dans le Task.Run (() => ...) s'exécutera de manière asynchrone

Brève explication: avec Task t = Task.Run (() => ...) nous commençons une nouvelle Task , le "bizarre "est une expression Lambda, en gros nous transmettons une méthode anonyme à la méthode Run qui sera exécutée par la Task
On attend ensuite que la tâche se termine avec t.Wait (); . La méthode Wait peut renvoyer une valeur, vous pouvez renvoyer une valeur à partir d'une méthode anonyme comme n'importe quelle méthode, avec le mot-clé return

Remarque: Ceci peut, mais ne doit pas être fait. Voir la réponse de Sean pour en savoir plus


0 commentaires

4
votes

Toute implémentation qui change fondamentalement quelque chose de sync à async impliquera un changement de signature. Toute autre approche ne fonctionnera tout simplement pas correctement. Fondamentalement: asynchroniser et synchroniser demander différentes API, ce qui signifie: différentes signatures. C'est inévitable, et franchement "Comment convertir une méthode synchrone en méthode asynchrone sans changer sa signature?" est un problème insoluble (et plus probablement: la mauvaise question). Je suis désolé s'il semble que je ne réponds pas à la question ici, mais ... parfois la réponse est "vous ne pouvez pas, et quiconque dit que vous pouvez vous tente sur une très mauvaise voie".


Dans le sens async/Task , le moyen le plus courant de le faire sans rompre la compatibilité est d'ajouter une méthode nouvelle / séparée, donc vous avez

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

et

SomeReturnType Foo();

rien de ce que Foo et FooAsync ici ont probablement des implémentations similaires mais différentes - une conçue pour exploiter async, une qui fonctionne de manière purement synchrone. Ce n'est pas une bonne idée d'usurper l'un en appelant l'autre - à la fois "sync over async" (la version synchrone appelant la version async) et "async over sync" (la version async appelant la version sync ) sont des anti-patterns, et doivent être évités (le premier est beaucoup plus dangereux que le second).


Si vous ne voulez vraiment pas faire cela, vous pouvez également faire des choses comme l'ajout d'un événement de rappel FooCompleted (ou similaire), mais: il s'agit toujours fondamentalement d'un changement de signature, et l'appelant devra toujours utiliser l'API différemment. Au moment où vous avez fait cela, vous auriez aussi bien pu faciliter la tâche du consommateur en ajoutant l'API Task à la place.


0 commentaires