Почему C # позволяет вам сделать асинхронную переопределение?

16

В C # при переопределении метода разрешается делать асинхронное переопределение, когда исходный метод не был. Это похоже на плохую форму.

Пример, который привел меня к этому, был следующим - меня привели, чтобы помочь с проблемой нагрузочного теста. Около 500 одновременно работающих пользователей процесс входа в систему будет нарушен в цикле перенаправления. IIS регистрировал исключения с сообщением «Асинхронный модуль или обработчик завершены, пока асинхронная операция еще не завершена». Некоторые поиски привели меня к мысли, что кто-то злоупотребляет async void, но мои быстрые поиски по источнику ничего не смогли найти.

К сожалению, я искал 'async \ svoid' (поиск по регулярному выражению), когда мне следовало искать что-то более похожее на 'async \ s [^ T]' (предполагая, что Задача не была полностью квалифицирована ... Вы понимаете, в чем дело).

То, что я позже нашел, было async override void onActionExecuting(...в базовом контроллере. Очевидно, что это должно быть проблемой, и это было. Исправление этого (сделав его синхронным на данный момент) решило проблему.

Вернемся к вопросу: почему вы можете пометить переопределение как асинхронное, когда вызывающий код не может его ожидать?

Питер Т. Лакомб младший
источник
3
пожалуйста, не кросс-пост : stackoverflow.com/questions/35817558/…
комнат
Что именно мешает вызывающей стороне ожидать переопределенного метода? Я не вижу препятствий.
Мартин Маат
@MartinMaat Вы можете только ждать методы, которые возвращаются Task.
Дерек Элкинс покинул SE
Возможно, это тонкость, которую я не заметил. Я должен был бы проверить, но я не вспоминаю предупреждение VS о вызове неасинхронных методов без ожидания.
Питер Т. Лакомб младший

Ответы:

16

Асинхронное ключевое слово позволяет метод использовать awaitсинтаксис в его определении. Я могу использовать awaitлюбой метод, который возвращает Taskтип независимо от того, является ли он асинхронным методом.

voidявляется допустимым (хотя и не поощряемым ) типом возврата для асинхронного метода, так почему бы его не разрешить? Со стороны asyncне позволяет ничего, что вы не могли бы сделать без него. Метод, с которым у вас возникли проблемы, мог бы быть написан так, чтобы он вел себя точно так же, не будучи асинхронным. Его определение было бы более многословным.

Для абонентов, async Tметод является нормальным методом , который возвращает T(который ограничен void, Taskили Task<A>). То, что это асинхронный метод, не является частью интерфейса. Обратите внимание, что следующий код недопустим:

interface IFoo {
    async void Bar();
}

Он (или аналогичный код в абстрактном классе) выдает следующее сообщение об ошибке в VS2012:

Модификатор async можно использовать только в методах, которые имеют тело оператора

Если я действительно хотел , чтобы метод в интерфейсе или родительском классе был типично асинхронным, я не могу использовать это asyncдля передачи информации. Если бы я хотел реализовать его с помощью awaitсинтаксиса, мне нужно было бы иметь возможность асинхронного переопределения (в случае родительского класса).

Дерек Элкинс покинул ЮВ
источник
1
Вы вообще не упоминаете override, но вот о чем вопрос.
Натан Тагги
4
@NathanTuggy Весь смысл ответа в том async, что интерфейс метода не меняется, только то, что синтаксически разрешено в его определении, поэтому не имеет значения, является ли это переопределением или нет.
Дерек Элкинс покинул SE
1
Пожалуйста, объясните это, а не предполагайте, что все уже знают все, что имеет отношение к делу.
Натан Тагги
2
@NathanTuggy Я чувствую, что объяснил это. Можете ли вы задать конкретный вопрос, о котором вас смущают, или вы думаете, что другой смущенный человек спросит? Единственное, что я могу добавить, - это указать, что asyncмодификатор можно применять только к реализациям. Вы не можете объявить метод асинхронным в интерфейсе, например, подчеркнув, что метод является асинхронным или нет, не является частью интерфейса.
Дерек Элкинс покинул SE
5
Положите объяснение в ответ , я имею в виду. Это не то, что комментарии в долгосрочной перспективе.
Натан Тагги
10

Единственная цель ключевого слова async - сделать ожидание в теле этой функции ключевым словом. Это необходимо для того, чтобы добавление функции await не нарушало существующий код. Microsoft решила использовать опцию «ждать». Для функции, которая не помечена как асинхронная, вы можете определить переменную с именем await без проблем.

Следовательно, async не является частью сигнатуры функции и не имеет семантического значения в сгенерированном коде IL. Компилятор должен знать, как правильно скомпилировать функцию. Он также дает указание компилятору гарантировать, что возвращаются только Task, Task <T> или void.

Эрик Джонсон
источник