Параметр за замовчуванням для CancellationToken


96

У мене є асинхронний код, до якого я хотів би додати a CancellationToken. Однак є багато реалізацій, де це не потрібно, тому я хотів би мати параметр за замовчуванням - можливо CancellationToken.None. Однак

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

врожайність

Значення типу '' не можна використовувати як параметр за замовчуванням, оскільки немає стандартних перетворень типу 'System.Threading.CancellationToken'

і

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

Значення параметра за замовчуванням для 'ct' має бути константою часу компіляції

Чи є спосіб отримати значення за замовчуванням CancellationToken?

Відповіді:


151

Виявляється, працює наступне:

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

що, згідно з документацією , трактується так само, як CancellationToken.None:

Ви також можете використовувати default(CancellationToken)оператор C #, щоб створити порожній маркер скасування.


4
Це саме те, що фреймворк наразі робить внутрішньо, але я б не робив цього у своєму коді. Подумайте, що відбувається з вашим кодом, якщо Microsoft змінить їх реалізацію і CancellationToken.Noneстане чимось більше default(CancellationToken).
noseratio 12.03.14

10
@Noseratio Це значною мірою порушить зворотну сумісність, тому я б не сподівався, що це станеться. А що ще default(CancellationToken)робити?
svick

3
@Noseratio: Ви занадто жорсткі. Швидше за все CancellationToken.None, вони фактично застаріють. Навіть Microsoft використовує default(CancellationToken)натомість. Наприклад, див. Ці результати пошуку з вихідного коду Entity Framework.
drowa

21
З властивості MSDN CancellationToken.None : "Ви також можете використовувати оператор C # за замовчуванням (CancellationToken), щоб створити порожній маркер скасування" . Жодна помилка не є помилкою, поки майбутня версія C # не прийме її як параметр за замовчуванням.
MuiBienCarlota

5
Те саме тут Для компенсації двох відсутніх проміжних комбінацій розробники можуть передавати None або значення CancellationToken за замовчуванням для параметра cancellationToken та значення null для параметра progress.
Арек Баль

25

Чи є спосіб отримати значення за замовчуванням для CancellationToken?

На жаль, це неможливо, як CancellationToken.Noneне і константа часу компіляції, що є вимогою до значень за замовчуванням у необов’язкових аргументах.

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

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

Task<x> DoStuff(....)
{
    return DoStuff(...., CancellationToken.None);
}

6
Це рекомендований спосіб вирішити це, як пояснюється в документації до асинхронного шаблону на основі завдань на MSDN (зокрема, у розділі Вибір перевантажень для забезпечення ).
Сем Гарвелл

CancellationToken.None == за замовчуванням true
eoleary

5
В чому справа CancellationToken cancellationToken = default(CancellationToken)? Тут також описано blogs.msdn.microsoft.com/andrewarnottms/2014/03/19/…
Рей

20

Ось кілька рішень у порядку зменшення загальної доброти:

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як значення за замовчуванням:

Task DoAsync(…, CancellationToken? ct = null)
{
     ct ?? CancellationToken.None 
}

Мені це рішення подобається найменше тому, що типи, що допускають обнулення, мають невеликі накладні витрати на виконання, а посилання на маркер скасування стають більш багатослівними через нульовий оператор злиття ??.


11

Інший варіант - використовувати Nullable<CancellationToken>параметр, встановити його за замовчуванням nullі мати справу з ним усередині методу:

Task<x> DoStuff(...., CancellationToken? ct = null) {
    var token = ct ?? CancellationToken.None;
    ...
}

блискуче! безумовно, це найкраща відповідь
Джон Хенкель,

4

Новіші версії C # дозволяють спростити синтаксис для типової версії (CancellationToken). Наприклад:

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

-1

Відповідь Тофутіма є одним із шляхів, але з коментарів я бачу, що люди мають проблеми з цим.

У цьому випадку я припустив, що можна використовувати такий спосіб:

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

і перевантажте його як:

Task<x> DoStuff(....)
{
    return DoStuff(...., CancellationToken.None);
}

Це компілюється, оскільки значення часу CancellationToken.Noneне потрібно під час компіляції.

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.