web-dev-qa-db-fra.com

Interfaces et méthodes asynchrones

J'ai une application. Cette application utilise une interface pour accéder à la base de données. Cette interface peut être implémentée par de nombreuses classes. Par exemple, on utilise EF 4.4, mais d'autres classes peuvent utiliser EF5 qui est plus efficace. À l'avenir, j'utiliserai peut-être EF6 car il utilise des méthodes asynchrones. Dans cet exemple, toutes les méthodes utilisent EF, mais peut-être que d'autres options peuvent être utilisées autrement.

L'application est codée une fois, en utilisant l'interface, et selon le fichier de configuration, utilisez une implémentation ou l'autre, donc je n'ai besoin que de modifier le code en un seul endroit, le constructeur, pour ajouter la nouvelle option dans l'instanciation de la classe qui est affecté à l'interface.

Pour le moment, toutes les méthodes des classes ne sont pas async, mais à l'avenir, si j'utilise EF6, j'aimerais utiliser les méthodes asynchrones, donc je ne sais pas s'il est possible que la classe qui utilise EF6 et implémente l'interface peut utiliser les méthodes async.

Pour les méthodes asynchrones d'EF6, j'utiliserais le modèle async/awiat, donc dans la méthode de ma classe, j'ai besoin d'utiliser l'attribut async. Cela me permet d'utiliser le mot clé await lorsque j'appelle à la méthode asynchrone d'EF6.

Mais cette classe peut implémenter l'interface qui dans un premier temps est destinée aux méthodes synchrones?

Existe-t-il un moyen que dans l'application principale, je puisse utiliser de nombreuses implémentations sans avoir besoin de modifier le code? Certaines implémentations utiliseront des méthodes asynchrones tandis que d'autres seront synchrones.

49
Álvaro García

async ne fait pas partie de la signature, vous n'avez donc pas vraiment besoin de vous soucier de savoir si la méthode implémentant l'interface est async ou non, vous devez seulement vous préoccuper de la types des propriétés, le type de retour, le nom de la méthode et l'accessibilité.

La différence réelle est que vos méthodes async devront renvoyer un Task ou un Task<T>, alors que les méthodes non asynchrones retournent très probablement actuellement void ou un certain type, T directement.

Si vous voulez "pérenniser" votre application, une option consiste à vous assurer que toutes vos interfaces renvoient Task ou Task<T> et que pour vos implémentations EF4/EF5, vous encapsulez vos résultats dans une tâche terminée même s'ils sont exécutés de manière synchrone.

Task.FromResult a été ajouté dans .NET 4.5, mais si vous ne l'avez pas, vous pouvez écrire le vôtre assez facilement:

public static Task<T> FromResult<T>(T result)
{
    var tcs = new TaskCompletionSource<T>();
    tcs.SetResult(result);
    return tcs.Task;
}

Vous pouvez également écrire une méthode CompletedTask qui renvoie simplement une tâche déjà terminée: (Elle met en cache une seule tâche pour des raisons d'efficacité.)

private static Task _completedTask;
public static Task CompletedTask()
{
    return _completedTask ?? initCompletedTask();
}

private static Task initCompletedTask()
{
    var tcs = new TaskCompletionSource<object>();
    tcs.SetResult(null);
    _completedTask = tcs.Task;
    return _completedTask;
}

Ces deux méthodes simplifieront le processus consistant à renvoyer toutes vos méthodes vers un type de Task, bien que cela rendra votre code un peu plus compliqué jusqu'à ce que vous puissiez utiliser C # 5.0 pour pouvoir await le résultat.

58
Servy