web-dev-qa-db-fra.com

Comment forcer les remplacements d'enfants asynchrones dans C # 5.0

Je travaille sur un système dans lequel plusieurs objets clients sont censés implémenter une fonction particulière via une interface, et je veux que cette fonction s'exécute de manière asynchrone avec les continuations (je m'attends à ce que les implémentations soient liées aux E/S et souhaitent assurez-vous que tous les objets clients remplissent cette fonction dès que possible). J'utilise le rafraîchissement CTP Async Visual Studio pour SP1, avec C # "5.0".

Quelle est la pratique recommandée pour appliquer le comportement asynchrone dans les objets enfants de ma classe abstraite (voir ci-dessous)? Je ne peux pas (apparemment) imposer l'utilisation des méthodes "asynchrones" en utilisant l'approche de méthode virtuelle. Je ne peux exiger qu'un type de retour "Tâche". Est-ce à dire que je ne devrais pas essayer d'exiger du tout un comportement asynchrone dans les objets enfants? Dans ce cas, le type de retour doit-il être simplement "nul"?

L'interface publique est une conséquence malheureuse de la conception du système en ce moment, mais c'est un problème distinct. De toute évidence, je ne pouvais contraindre personne à être asynchrone qui contourne "BaseFoo" et implémente simplement l'interface "IFoo".

Voici le code:

public interface IFoo
{
    void Bar(); //NOTE: Cannot use 'async' on methods without bodies.
}

public abstract class BaseFoo : IFoo
{
    public async void Bar()
    {
        await OnBar(); //QUESTION: What is the right "async delegation" pattern?
    }

    protected virtual async Task OnBar()
    {
        await TaskEx.Yield();
    }
}

public class RealFoo : BaseFoo //NOTE: May be implemented by 3rd party
{
    protected override async Task OnBar()
    {
        //CLIENT: Do work, potentially awaiting async calls

        await TaskEx.Yield(); //SECONDARY QUESTION: Is there a way to avoid this if there are no 'awaits' in the client's work?
    }
}
44
Lars Kemmann

Qu'une méthode soit implémentée en utilisant async/await ou non est un détail implémentation. Comment la méthode doit se comporter est un détail du contrat, qui doit être spécifié de manière normale.

Notez que si vous faites en sorte que la méthode retourne un Task ou un Task<T>, il est plus évident qu'il est censé être asynchrone et sera probablement difficile à implémenter sans étant asynchrone.

D'un autre côté, s'il existe une implémentation (par exemple à des fins de test) où les expressions await seraient jamais incomplètes, pourquoi voudriez-vous forcer quelqu'un à écrire une méthode asynchrone sans await appelle quand même? Vous attendez que les implémentations soient liées aux E/S, mais il y aura peut-être des cas spéciaux où les implémentations voudront utiliser des données codées en dur, etc.

Fondamentalement, vous devez gérer cela dans la documentation de la méthode - si vous ne pouvez pas faire confiance aux implémenteurs pour lire cela, vous n'avez de toute façon aucune chance :(

83
Jon Skeet

En plus de la réponse de Jon, si vous suivez le modèle asynchrone basé sur les tâches alors les noms de vos méthodes doivent être suffixés avec Async, qui auto-documente qu'il s'agit d'une méthode asynchrone.

Si vous implémentez une interface

public interface IFoo
{
    Task BarAsync();
}

il doit être évident que cela doit être implémenté avec le mot clé async.

16
dav_i