Параметр по умолчанию для CancellationToken

У меня есть асинхронный код, к которому я хотел бы добавить CancellationToken. Однако во многих реализациях в этом нет необходимости, поэтому я хотел бы иметь параметр по умолчанию - возможно, CancellationToken.None. Тем не мение,

Task<x> DoStuff(...., CancellationToken ct = null)

дает

Значение типа '' нельзя использовать в качестве параметра по умолчанию, поскольку нет стандартных преобразований в тип 'System.Threading.CancellationToken'

и

Task<x> DoStuff(...., CancellationToken ct = CancellationToken.None)

Значение параметра по умолчанию для ct должно быть константой времени компиляции.

Есть ли способ установить значение по умолчанию для CancellationToken?


person tofutim    schedule 12.03.2014    source источник
comment
Я также видел new CancellationToken(), что в точности эквивалентно default, поскольку CancellationToken - это структура.   -  person Palec    schedule 13.05.2021


Ответы (5)


Оказывается, работает следующее:

Task<x> DoStuff(...., CancellationToken ct = default(CancellationToken))

...or:

Task<x> DoStuff(...., CancellationToken ct = default) // C# 7.1 and later

который, в соответствии с документация интерпретируется так же, как CancellationToken.None:

Вы также можете использовать оператор C # default(CancellationToken) для создания пустого токена отмены.

person tofutim    schedule 12.03.2014
comment
Именно этим занимается фреймворк в настоящее время. внутри, но я бы не делал это в своем коде. Подумайте, что произойдет с вашим кодом, если Microsoft изменит их реализацию, и CancellationToken.None станет чем-то большим, чем default(CancellationToken). - person noseratio; 13.03.2014
comment
@Noseratio Это сильно нарушит обратную совместимость, поэтому я бы не ожидал, что это произойдет. А что еще default(CancellationToken) делать? - person svick; 13.03.2014
comment
@svick, если моя библиотека ссылается на свойство System.Threading.CancellationToken.None, а значение CancellationToken.None изменится в будущей версии mscorlib.dll, как это сломает мою библиотеку (код IL)? Однако я бы не стал делать прогнозов относительно default(CancellationToken). - person noseratio; 13.03.2014
comment
@Noseratio. Если ваша библиотека использует default(CancellationToken) (или new CancellationToken()), что я считаю допустимым для любого типа значения, и это значение начало вести себя по-другому, это нарушит совместимость. - person svick; 13.03.2014
comment
@svick, я понимаю вашу точку зрения, но нигде в MSDN не упоминается, что CancellationToken.None то же самое, что default(CancellationToken). Технически это может стать static readonly структурой с полями, отличными от значений по умолчанию, что маловероятно, но возможно. Тогда, если бы моя библиотека использовала CancellationToken.None, я бы остался совместимым. Не так, если он использовал default(CancellationToken). - person noseratio; 13.03.2014
comment
@Noseratio: Ты слишком жесткий. Скорее всего, CancellationToken.None станет устаревшим де-факто. Даже Microsoft вместо этого использует default(CancellationToken). Например, см. эти результаты поиска из исходного кода Entity Framework. - person drowa; 13.02.2015
comment
@drowa, мир здесь. CancellationToken.None вряд ли будет устаревшим, но с тех пор я использую себя default(CancellationToken) :) Плюс к OP. - person noseratio; 13.02.2015
comment
Из свойства CancellationToken.None в MSDN: Вы также можете использовать оператор C # default (CancellationToken) для создания пустого токена отмены. Ни один из них не является ошибкой, пока будущая версия C # не примет его в качестве параметра по умолчанию. - person MuiBienCarlota; 30.07.2015
comment
То же самое здесь Чтобы компенсировать две отсутствующие промежуточные комбинации, разработчики могут передавать None или CancellationToken по умолчанию для параметра cancellationToken и null для параметра прогресса. - person Arek Bal; 05.08.2015

Есть ли способ иметь значение по умолчанию для CancellationToken?

К сожалению, это невозможно, поскольку CancellationToken.None не является константой времени компиляции, что является требованием для значений по умолчанию в дополнительных аргументах.

Однако вы можете добиться того же эффекта, создав перегруженный метод вместо того, чтобы пытаться использовать параметры по умолчанию:

Task<x> DoStuff(...., CancellationToken ct)
{
    //...
}

Task<x> DoStuff(....)
{
    return DoStuff(...., CancellationToken.None);
}
person Reed Copsey    schedule 12.03.2014
comment
Это рекомендуемый способ справиться с этим, как описано в Асинхронном шаблоне на основе задач. документации MSDN (в частности, в разделе Выбор предоставляемых перегрузок). - person Sam Harwell; 12.03.2014
comment
CancellationToken.None == по умолчанию true - person eoleary; 30.01.2018
comment
Что с CancellationToken cancellationToken = default(CancellationToken)? Здесь также описано blogs.msdn.microsoft. ru / andrewarnottms / 2014/03/19 / - person Ray; 03.04.2018

Вот несколько решений в порядке убывания их полезности:

1. Использование default(CancellationToken) в качестве значения по умолчанию:

Task DoAsync(CancellationToken ct = default(CancellationToken)) { … }

Семантически CancellationToken.None был бы идеальным кандидатом в качестве значения по умолчанию, но не может использоваться как таковой, потому что он не является константой времени компиляции. default(CancellationToken) - следующая лучшая вещь, потому что это константа времени компиляции и официально задокументировано как эквивалент CancellationToken.None.

2. Предоставление перегрузки метода без параметра CancellationToken:

Или, если вы предпочитаете перегрузку методов по необязательным параметрам (см. this и этот вопрос по этой теме):

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, связаны с небольшими накладными расходами во время выполнения, а ссылки на токен отмены становятся более подробными из-за оператора объединения с нулевым значением ??.

person stakx - no longer contributing    schedule 01.03.2017

Другой вариант - использовать параметр Nullable<CancellationToken>, по умолчанию null и работать с ним внутри метода:

Task<x> DoStuff(...., CancellationToken? ct = null) {
    var token = ct ?? CancellationToken.None;
    ...
}
person Todd Menier    schedule 09.07.2016
comment
молодец! безусловно, это лучший ответ - person John Henckel; 27.06.2019

Более новые версии C # допускают упрощенный синтаксис для версии по умолчанию (CancellationToken). Например.:

Task<x> DoStuff(...., CancellationToken ct = default)
person Alexei - check Codidact    schedule 29.01.2020