Ошибка: нельзя использовать асинхронность для методов без тел. Как принудительно переопределить асинхронный дочерний элемент?

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

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

Публичный интерфейс сейчас является досадным следствием дизайна системы, но это отдельная тема. Очевидно, я не мог заставить кого-либо быть асинхронным, кто обходит «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?
    }
}

person Lars Kemmann    schedule 08.06.2011    source источник


Ответы (2)


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

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

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

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

person Jon Skeet    schedule 08.06.2011
comment
Отлично! Спасибо большое! Различие между реализацией и поведением очень полезно; Я не слышал этого раньше w.r.t. асинхронное ожидание. Я решил оставить контракт Bar как «недействительный» как в IFoo, так и в BaseFoo, и позволить RealFoo определить асинхронность. Это также упрощает возвращаемое значение для RealFoo.Bar. - person Lars Kemmann; 08.06.2011
comment
@Lars: у меня возникло бы искушение использовать тип возвращаемого значения Task, а не void везде, где вы можете - void в основном там, чтобы вы могли реализовывать обработчики событий с асинхронными методами. Часто бывает удобно дождаться завершения асинхронного метода и т. д., и Task упрощает эту задачу. - person Jon Skeet; 08.06.2011
comment
Хорошо, это имеет смысл. Я еще немного рассмотрю последствия возврата Task. Еще раз спасибо! - person Lars Kemmann; 10.06.2011

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

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

public interface IFoo
{
    Task BarAsync();
}

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

person dav_i    schedule 23.10.2014