Одной из менее обсуждаемых функций С# 7 является "обобщенные типы возврата async", который описан Microsoft как:
Возвращение объекта Task из методов async может привести к узким местам производительности в определенных путях. Задача является ссылочным типом, поэтому ее использование означает выделение объекта. В тех случаях, когда метод, объявленный с помощью модификатора async, возвращает результат кэширования или завершает синхронно, дополнительные распределения могут стать значительными временными затратами в критических разделах кода производительности. Это может стать очень дорогостоящим, если эти распределения происходят в плотных циклах.
Новая функция языка означает, что методы async могут возвращать другие типы в дополнение к Task
, Task<T>
и void
. Возвращаемый тип должен удовлетворять шаблону async, то есть метод GetAwaiter должен быть доступен. В качестве одного из конкретных примеров тип ValueTask был добавлен в среду .NET для использования этой новой языковой функции:
Это звучит здорово, но я не могу на всю жизнь найти какой-нибудь пример, который не просто использует тип запаса ValueTask<T>
. Я хочу создать свой собственный тип типа Task. В частности, я хочу тип, который ведет себя как Task<T>
, но с более функциональным стилем обработки ошибок.
Вот тип, который я использую для обработки функциональных ошибок в моем проекте:
public class Try<T> {
public T Data { get; }
public Exception Error { get; }
public bool HasData => Error == null;
public bool HasError => Error != null;
public Try(T data) {
Data = data;
}
public Try(Exception error) {
Error = error;
}
}
Вот что я думаю, что мой пользовательский ожидаемый тип должен выглядеть так:
public class TryTask<T> : Task<Try<T>> {
public TryTask(Func<Try<T>> func)
: base(func) { }
//GetAwaiter is defined on base type, so we should be okay there
}
Все это компилируется, пока я не попытаюсь использовать его как возвращаемый тип async:
async TryTask<int> DoWhatever() {
return await new TryTask<int>(() => new Try<int>(1));
}
Этот метод даст ошибку компилятора. Тип возврата метода async должен быть недействительным, Задача или Задача.
Как мне сделать это или что-то вроде этого компилировать?
Update:
Чтобы подтвердить, я использую выпуск VS 2017 от 3/7, и я могу использовать другие функции С# 7 в моем проекте, такие как локальные функции.
Я также пробовал использовать ValueTask
и получаю ту же ошибку компилятора.
static async ValueTask<int> DoWhatever() {
return await new ValueTask<int>(1);
}
Вот еще одно сообщение, которое проливает свет на то, что происходит.
Как получить новую семантику async, работающую в VS2017 RC?
По-видимому, должен быть определен отдельный тип "построитель метода", и специальные атрибуты должны применяться к ожидаемому типу. Я не знаю, есть ли у меня время, чтобы вникать в это. Это скорее похоже на метапрограммирование хакера, чем "языковая функция".