Veamos un ejemplo concreto del uso de TaskCompletionSource para reemplazar una llamada. En una guía anterior hablamos de una aplicación que genera imágenes; supongamos que necesitas tu aplicación para subir esas imágenes a algún lugar. Imagina que hay un servicio de almacenamiento de archivos en la nube llamado «MyBox» que tiene una biblioteca .NET, y el método de biblioteca para subir un archivo es el siguiente:
1publicstaticvoidUploadFile(nombre de la cadena, byte[] datos, Action<bool> onCompleted);
csharp
Consultando la documentación de la biblioteca, se encuentra que onCompletado es una llamada de retorno que se invoca cuando la carga se completa, con un valor de verdadero si la carga tiene éxito y falso si la carga falla. Para subir un archivo mediante este método de biblioteca, debe hacer algo como lo siguiente, suponiendo que su aplicación tenga algo en lo que mostrar el texto denominado statusText:
12345678910publicasyncevitarSubirBotónClick(){ statusText.Text ="Generar Imagen...";byte[] imageData =awaitGenerateImage(); statusText. Texto ="Cargando Imagen..."; MyBox.UploadFile("imagen.jpg", imagenDatos, éxito ={[statusText.Text = éxito ?string.Empty : "Error Uploading";});}
csharp
Esto funciona bien, pero realmente preferirías usar el método de asincronización/espera en lugar del de devolución de llamada, especialmente si planeas usar mucho esa biblioteca en tu aplicación. Puede hacerlo creando un método de ayuda que utilice TaskCompletionSource para ocultar la devolución de llamada a las personas que llaman al método de ayuda. En primer lugar, defina una instancia de TaskCompletionSource. Acepta un parámetro genérico que representa el tipo de lo que sea que se quiera devolver. En este caso, queremos devolver el valor de la variable de éxito, que es una booleana, así que usa bool como parámetro genérico.
1var taskCompletionSource =newTaskCompletionSource<bool.;();
csharp
Pongamos esa definición dentro de una clase/método de ayuda.
1234567publicstaticclassMyBoxHelper{publicstatic Task<bool>UploadFile(nombre de la cadena, byte[] datos){var taskCompletionSource =newTaskCompletionSource<bool>();}}
csharp
Acercándonos al método ahora, también necesitamos añadir la llamada al método de la biblioteca «MyBox», que hará la carga:
12345Tarea PúblicaTarea<bool...;UploadFile(nombre de la cadena, byte[] datos){var taskCompletionSource =newTaskCompletionSource<bool...;(); MyBox.UploadFile(nombre, datos, éxito =...{});}
csharp
A continuación, tenemos que decirle a la Fuente de Terminación de Tareas cuando su operación ha terminado, y pasarle el resultado de la operación. Hay un método SetResult en TaskCompletionSource para ese propósito exacto. No es sorprendente que debamos llamarlo en la llamada de retorno, cuando conocemos el resultado:
12345678Tarea pública estática<bool...; UploadFile(nombre de la cadena, byte[] datos){var taskCompletionSource =newTaskCompletionSource<bool...;(); MyBox.UploadFile(nombre, datos, éxito =...;{ taskCompletionSource.SetResult(éxito);});}
csharp
Por último, pero no menos importante, necesitamos pedirle a la Fuente de Terminación de Tareas que nos dé una tarea. Esto resulta ser súper fácil ya que TaskCompletionSource tiene una propiedad llamada Task! Sólo devuelve eso directamente.
123456789Tarea pública estática<bool...;UploadFile(nombre de la cadena, byte[] datos){var taskCompletionSource =newTaskCompletionSource<bool...;(); MyBox.UploadFile(nombre, datos, éxito =...;{ taskCompletionSource.SetResult(success);});return taskCompletionSource.Task;}
csharp
Para evitar tener una Tarea que nunca termina, asegúrese de agregar el manejo de excepciones para que la Tarea pueda ser completada si surge algún problema. En el caso de una excepción, puedes simplemente cancelar usando SetCanceled (lo que, a su vez, arrojaría una excepción genérica de TaskCanceledException), pero, aún mejor, sería proporcionar la excepción que causó el problema usando SetException.
12345678910111213141516Tarea pública estática<bool>UploadFile(nombre de la cadena, byte[] datos){var taskCompletionSource =newTaskCompletionSource<bool>();try{ MyBox. csharp¡Eso es! Ahora, cada vez que MyBox.UploadFile llame a la devolución de llamada o lance una excepción, la Tarea generada por la Fuente de Terminación de Tareas se completará para reflejar eso.
Una vez que tenga su método de ayuda en su lugar, ahora puede esperarlo en cualquier lugar de su código sin tener que usar devoluciones de llamada. Vamos a actualizar nuestro manejador de eventos de clicks de botón:
12345678publicasyncvotoSubirBotónClicó(){ statusText.Text ="Generar Imagen...";byte[] imageData =awaitGenerateImage(); statusText. Texto ="Cargando Imagen...";bool success =await MyBoxHelper.UploadFile("image.jpg", imageData); statusText.Text = success ?string.Empty : "Error Uploading";}csharp
¡Maravilloso! Escondiendo los detalles de implementación de la devolución de llamada dentro de su clase de ayuda, este código puede ahora tener un flujo lineal con menos indentación, ambos beneficios de usar asincronía/espera.