Pregunta

estaba leyendo La naturaleza de la fuente de finalización de tareas, una publicación de Stephen Toub.

public static Task RunAsync(Action action)
{
    var tcs = new TaskCompletionSource<Object>();
    ThreadPool.QueueUserWorkItem(_ =>
    {
        try
        {
            action();
            tcs.SetResult(null);
        }
        catch(Exception exc) { tcs.SetException(exc); }
    });
    return tcs.Task;
}

Como ya no nos importa cuál sea el tipo de T es que he optado por usar Object.Entonces, cuando el Action se ejecuta con éxito, SetResult todavía se utiliza para hacer la transición Task en el RanToCompletion estado final;sin embargo, dado que el valor del resultado real es irrelevante, null se utiliza. Finalmente, RunAsync devoluciones Task en vez de Task<Object>.Por supuesto, el instanciado taskEl tipo sigue siendo Task<Object>, pero no necesitamos referirnos a él como tal, y el consumidor de este método no necesita preocuparse por esos detalles de implementación.

No entiendo particularmente por qué el método debería regresar Task en vez de Task<object> (por eso enfaticé la frase en negrita).Sé que el método está configurado para regresar Task pero tcs es un TaskCompletionSource<Object>, no TaskCompletionSource (lo cual está mal, creo).

¿Fue útil?

Solución

No existe un no genérico. TaskCompletionSource y considerando que lo único que quieres es una tarea sin resultado, el resultado no importa.La persona que llama no sabe y no le importa en este caso que la Tarea sea en realidad una Task<object>, La persona que llama simplemente awaitAsí es y obtiene una excepción si la hay.La persona que llama desconoce el resultado real.

Por supuesto, esto se ve facilitado por el hecho de que Task<T> hereda de Task


También es común encontrar un Task<bool> que devuelve falso, o Task<int> con 0.

Otros consejos

No hay no genérico TaskCompletionSource clase para crear instancias de Task que no son casos de Task<T>.Esto deja dos opciones para el parámetro de tipo genérico para TaskCompletionSource<T> cuando no le importa (o no proporciona) el valor de retorno:

  1. Utilice un tipo existente arbitrario, como object, como tipo de devolución.Establezca el valor en null para indicar la finalización de la tarea.
  2. Utilice un tipo no público específico y establezca el valor en null para indicar la finalización de la tarea.

Cuando creo un TaskCompletionSource<T> instancia con el fin de proporcionar una Task sin valor de retorno, prefiero usar un tipo no público dedicado para garantizar que el código utilizado no confunda lo devuelto Task como una instancia de Task<T> donde el resultado tiene significado.

Primero, defino la siguiente clase (puede ser una private sealed class si está anidado dentro de otro tipo):

internal sealed class VoidResult
{
}

Entonces, en lugar de utilizar TaskCompletionSource<object> para la fuente de finalización, uso TaskCompletionSource<VoidResult>.desde el VoidResult tipo no es accesible llamando al código, el usuario no podrá transmitir el Task oponerse a una instancia de Task<VoidResult>.

No entiendo particularmente por qué el método debería regresar Task en vez de Task<object>

porque cuando regreses Task<Object> significa que cuando este método se complete producirá algún valor útil de tipo Object.En este caso no estamos produciendo ningún resultado, es por eso que Stephen decidió regresar. Task.

Si estamos tratando con Func<Object> luego regresando Task<Object> Sería apropiado, ya que Func producirá algún resultado, podemos optar por devolverlo.

Por qué TaskCompletionSource<Object>, no TaskCompletionSource?

Porque no existe tal cosa.No hay no genérico TaskCompletionSource.

Si devolviste un Task<object>, entonces var result = await RunAsync(...) siempre volvería null, ya que eso es a lo que estás configurando el resultado.

Al cliente no le importa esto, así que simplemente devuelve un Task.

Lo ideal sería utilizar un TaskCompletionSource internamente, en lugar de TaskCompletionSource<object>, y simplemente llama a algo como SetCompleted() en lugar de SetResult(null).Pero ese tipo no existe.

Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top