У меня есть асинхронный код, к которому я хотел бы добавить CancellationToken
. Однако есть много реализаций, в которых это не нужно, поэтому я хотел бы иметь параметр по умолчанию - возможно CancellationToken.None
. Однако,
Task<x> DoStuff(...., CancellationToken ct = null)
дает
Значение типа '' нельзя использовать в качестве параметра по умолчанию, поскольку нет стандартных преобразований в тип 'System.Threading.CancellationToken'
а также
Task<x> DoStuff(...., CancellationToken ct = CancellationToken.None)
Значение параметра по умолчанию для ct должно быть константой времени компиляции.
Есть ли способ установить значение по умолчанию для CancellationToken
?
CancellationToken.None
станет чем-то большимdefault(CancellationToken)
.default(CancellationToken)
делать?CancellationToken.None
они станут де-факто устаревшими. Даже Microsoft используетdefault(CancellationToken)
вместо этого. Например, просмотрите эти результаты поиска в исходном коде Entity Framework.К сожалению, это невозможно, так как
CancellationToken.None
это не константа времени компиляции, которая является требованием для значений по умолчанию в дополнительных аргументах.Однако вы можете добиться того же эффекта, создав перегруженный метод вместо того, чтобы пытаться использовать параметры по умолчанию:
Task<x> DoStuff(...., CancellationToken ct) { //... } Task<x> DoStuff(....) { return DoStuff(...., CancellationToken.None); }
источник
CancellationToken cancellationToken = default(CancellationToken)
? Также здесь описано blogs.msdn.microsoft.com/andrewarnottms/2014/03/19/…Вот несколько решений в порядке убывания их полезности:
1. Использование
default(CancellationToken)
по умолчанию:Task DoAsync(CancellationToken ct = default(CancellationToken)) { … }
Семантически это
CancellationToken.None
был бы идеальный кандидат на значение по умолчанию, но его нельзя использовать как таковой, потому что он не является константой времени компиляции.default(CancellationToken)
- следующая лучшая вещь, потому что это константа времени компиляции и официально задокументирована как эквивалентнаяCancellationToken.None
.2. Предоставление перегрузки метода без
CancellationToken
параметра:Или, если вы предпочитаете перегрузку метода необязательным параметрам (см. Этот и этот вопрос по этой теме):
Task DoAsync(CancellationToken ct) { … } // actual method always requires a token Task DoAsync() => DoAsync(CancellationToken.None); // overload producing a default token
Для методов интерфейса то же самое можно сделать с помощью методов расширения:
interface IFoo { Task DoAsync(CancellationToken ct); } static class Foo { public static Task DoAsync(this IFoo foo) => foo.DoAsync(CancellationToken.None); }
Это приводит к более тонкому интерфейсу и избавляет разработчиков от явного написания перегрузки метода пересылки.
3. Сделать параметр допускающим значение NULL и использовать в
null
качестве значения по умолчанию:Task DoAsync(…, CancellationToken? ct = null) { … ct ?? CancellationToken.None … }
Мне нравится это решение хотя бы потому, что типы, допускающие значение NULL, связаны с небольшими издержками времени выполнения, а ссылки на токен отмены становятся более подробными из-за оператора объединения NULL
??
.источник
Другой вариант - использовать
Nullable<CancellationToken>
параметр по умолчаниюnull
и обрабатывать его внутри метода:Task<x> DoStuff(...., CancellationToken? ct = null) { var token = ct ?? CancellationToken.None; ... }
источник
Более новые версии C # допускают упрощенный синтаксис для версии по умолчанию (CancellationToken). Например:
Task<x> DoStuff(...., CancellationToken ct = default)
источник
Ответ Тофутима односторонний, но из комментариев я вижу, что у людей есть проблемы с этим.
В этом случае я предположил, что можно использовать следующий метод:
Task<x> DoStuff(...., CancellationToken ct) { }
и перегружаем его как:
Task<x> DoStuff(....) { return DoStuff(...., CancellationToken.None); }
Это компилируется, потому что значение
CancellationToken.None
не требуется во время компиляции.источник