Parámetro predeterminado para CancellationToken


96

Tengo un código asincrónico al que me gustaría agregar un código CancellationToken. Sin embargo, hay muchas implementaciones en las que esto no es necesario, por lo que me gustaría tener un parámetro predeterminado, tal vez CancellationToken.None. Sin embargo,

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

rendimientos

Un valor de tipo '' no se puede usar como parámetro predeterminado porque no hay conversiones estándar para escribir 'System.Threading.CancellationToken'

y

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

El valor del parámetro predeterminado para 'ct' debe ser una constante en tiempo de compilación

¿Hay alguna forma de tener un valor predeterminado para CancellationToken?

Respuestas:


151

Resulta que lo siguiente funciona:

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

que, según la documentación , se interpreta igual que CancellationToken.None:

También puede usar la default(CancellationToken)instrucción C # para crear un token de cancelación vacío.


4
Esto es exactamente lo que el marco actualmente hace internamente, pero yo no lo haga en mi código. Piense en lo que pasa con su código si Microsoft cambia su implementación, y se CancellationToken.Noneconvierte en algo más que default(CancellationToken).
noseratio

10
@Noseratio Eso rompería enormemente la compatibilidad con versiones anteriores, así que no esperaría que eso suceda. ¿Y qué más haría default(CancellationToken)?
svick

3
@Noseratio: Estás siendo demasiado rígido. Lo más probable es que CancellationToken.Nonese vuelva obsoleto de facto. Incluso Microsoft está usando en su default(CancellationToken)lugar. Por ejemplo, vea estos resultados de búsqueda del código fuente de Entity Framework.
drowa

21
De MSDN CancellationToken.None Property : "También puede usar la instrucción predeterminada de C # (CancellationToken) para crear un token de cancelación vacío" . Ninguno es un error hasta que una versión futura de C # lo acepte como parámetro predeterminado.
MuiBienCarlota

5
Lo mismo aquí Para compensar las dos combinaciones intermedias faltantes, los desarrolladores pueden pasar None o un CancellationToken predeterminado para el parámetro cancellationToken y null para el parámetro de progreso.
Arek Bal

25

¿Hay alguna forma de tener un valor predeterminado para CancellationToken?

Desafortunadamente, esto no es posible, ya CancellationToken.Noneque no es una constante de tiempo de compilación, que es un requisito para los valores predeterminados en los argumentos opcionales.

Sin embargo, puede proporcionar el mismo efecto si crea un método sobrecargado en lugar de intentar utilizar los parámetros predeterminados:

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

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

6
Esta es la forma recomendada de manejar esto, como se explica en la documentación del patrón asincrónico basado en tareas en MSDN (específicamente en la sección Elección de las sobrecargas para proporcionar ).
Sam Harwell

CancellationToken.None == default true
eoleary

5
¿Qué pasa con CancellationToken cancellationToken = default(CancellationToken)? También se describe aquí blogs.msdn.microsoft.com/andrewarnottms/2014/03/19/…
Ray

20

Aquí hay varias soluciones, en orden descendente de bondad general:

1. Usando default(CancellationToken)como valor predeterminado:

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

Semánticamente, CancellationToken.Nonesería el candidato ideal para el valor predeterminado, pero no se puede usar como tal porque no es una constante en tiempo de compilación. default(CancellationToken)es la mejor opción porque es una constante en tiempo de compilación y está oficialmente documentada como equivalente aCancellationToken.None .

2. Proporcionar una sobrecarga de método sin un CancellationTokenparámetro:

O, si prefiere las sobrecargas de métodos sobre los parámetros opcionales (consulte esta y esta pregunta sobre ese tema):

Task DoAsync(CancellationToken ct) {  } // actual method always requires a token
Task DoAsync() => DoAsync(CancellationToken.None); // overload producing a default token

Para los métodos de interfaz, se puede lograr lo mismo utilizando métodos de extensión:

interface IFoo
{
    Task DoAsync(CancellationToken ct);
}

static class Foo
{
    public static Task DoAsync(this IFoo foo) => foo.DoAsync(CancellationToken.None);
}

Esto da como resultado una interfaz más delgada y evita que los implementadores escriban explícitamente la sobrecarga del método de reenvío.

3. Hacer que el parámetro sea anulable y usar nullcomo valor predeterminado:

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

Me gusta esta solución menos porque los tipos que aceptan valores NULL vienen con una pequeña sobrecarga de tiempo de ejecución, y las referencias al token de cancelación se vuelven más detalladas debido al operador de fusión nulo ??.


11

Otra opción es usar un Nullable<CancellationToken>parámetro, establecerlo por defecto nully tratarlo dentro del método:

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

¡brillante! con mucho, esta es la mejor respuesta
John Henckel

4

Las versiones más recientes de C # permiten una sintaxis simplificada para la versión predeterminada (CancellationToken). P.ej:

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

-1

La respuesta de Tofutim es unidireccional, pero por los comentarios veo que la gente tiene problemas con eso.

En ese caso, sugerí que uno puede tener un método de la siguiente manera:

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

y sobrecargarlo como:

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

Esto se compila porque CancellationToken.Noneno se requiere el valor de en el momento de la compilación.

Al usar nuestro sitio, usted reconoce que ha leído y comprende nuestra Política de Cookies y Política de Privacidad.
Licensed under cc by-sa 3.0 with attribution required.