Как заставить асинхронные дочерние переопределения в C # 5.0 - PullRequest
44 голосов
/ 08 июня 2011

Я работаю в системе, в которой несколько клиентских объектов должны реализовывать определенную функцию через интерфейс, и я хочу, чтобы эта функция выполнялась асинхронно с продолжениями (я ожидаю, что реализации будут привязаны к вводу / выводу и хотим, чтобы все клиентские объекты выполнили эту функцию как можно скорее). Я использую Visual Studio Async CTP Refresh для SP1 с C # «5.0».

Какова рекомендуемая практика для принудительного асинхронного поведения в дочерних объектах моего абстрактного класса (см. Ниже)? Я не могу (по-видимому) навязать использование асинхронных методов с использованием подхода виртуальных методов. Я могу требовать только тип возврата «Задача». Означает ли это, что я не должен пытаться вообще требовать асинхронного поведения в дочерних объектах? В таком случае, должен ли возвращаемый тип быть просто 'void'?

Публичный интерфейс сейчас является печальным следствием проектирования системы, но это отдельная проблема. Очевидно, я не мог заставить никого быть асинхронным, который обходит «BaseFoo» и просто реализует интерфейс «IFoo».

Вот код:

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?
    }
}

Ответы [ 2 ]

81 голосов
/ 08 июня 2011

Реализован ли метод с использованием async / await или нет - это деталь реализация . То, как метод должен вести себя , является деталью контракта, которая должна быть указана обычным способом.

Обратите внимание, что если вы заставите метод возвращать Task или Task<T>, более очевидно, что он должен быть асинхронным и, вероятно, будет трудно реализовать без , являющегося асинхронным.

С другой стороны, если есть реализация (например, для целей тестирования), в которой выражения await не будут никогда неполными, почему вы хотите заставить кого-то написать асинхронный метод без await звонит в любом случае? Вы ожидаете, что реализации будут привязаны к IO, но, возможно, будут особые случаи, когда реализации захотят использовать жестко закодированные данные и т. Д.

По сути, вы должны разобраться с этим в документации к методу - если вы не можете доверять исполнителям, чтобы прочитать это, у вас все равно нет шансов: (

16 голосов
/ 23 октября 2014

В дополнение к ответу Джона, если вы следуете за Асинхронным шаблоном на основе задач , тогда имена ваших методов должны иметь суффикс Async, который сам документирует, что это асинхронный метод.

Если вы реализуете интерфейс

public interface IFoo
{
    Task BarAsync();
}

, должно быть очевидно, что это должно быть реализовано с ключевым словом async.

...