Business
Jobs
  • About Us
  • Solutions
    • Job Postings
      Post your job and receive qualified candidates in 48h.
    • Candidate Assessments
      500+ technical and psychological tests, plus anti-fraud.
    • Headhunting
      Tailor-made executive search from start to finish.
    • Payroll + EOR
      Payroll dispersal and EOR across 15+ LATAM countries.
  • Pricing
  • Jobs

0

346
Views
TaskCompletionSource arroja "Se intentó hacer la transición de una tarea a un estado final cuando ya se había completado"

Quiero usar TaskCompletionSource para envolver MyService que es un servicio simple:

 public static Task<string> ProcessAsync(MyService service, int parameter) { var tcs = new TaskCompletionSource<string>(); //Every time ProccessAsync is called this assigns to Completed! service.Completed += (sender, e)=>{ tcs.SetResult(e.Result); }; service.RunAsync(parameter); return tcs.Task; }

Este código está funcionando bien por primera vez. Pero la segunda vez que llamo a ProcessAsync simplemente el controlador de eventos para Completed se asigna nuevamente (se usa la misma variable service cada vez) y, por lo tanto, ¡se ejecutará dos veces! y la segunda vez lanza esta excepción:

intentar el estado final de la tarea de transición cuando ya se haya completado

No estoy seguro, ¿debería declarar el tcs como una variable de nivel de clase como esta:

 TaskCompletionSource<string> tcs; public static Task<string> ProccessAsync(MyService service, int parameter) { tcs = new TaskCompletionSource<string>(); service.Completed -= completedHandler; service.Completed += completedHandler; return tcs.Task; } private void completedHandler(object sender, CustomEventArg e) { tcs.SetResult(e.Result); }

Tengo que envolver muchos métodos con diferentes tipos de devolución y de esta manera tengo que escribir código perdido, variables, controladores de eventos, por lo que no estoy seguro de si esta es la mejor práctica en estos escenarios. Entonces, ¿hay alguna forma mejor de hacer este trabajo?

over 4 years ago · Santiago Trujillo
3 answers
Answer question

0

El problema aquí es que el evento Completed se genera en cada acción, pero TaskCompletionSource solo se puede completar una vez.

Todavía puede usar un TaskCompletionSource local (y debería hacerlo). Solo necesita anular el registro de la devolución de llamada antes de completar TaskCompletionSource . De esa manera, esta devolución de llamada específica con este TaskCompletionSource específico nunca se volverá a llamar:

 public static Task<string> ProcessAsync(MyService service, int parameter) { var tcs = new TaskCompletionSource<string>(); EventHandler<CustomEventArg> callback = null; callback = (sender, e) => { service.Completed -= callback; tcs.SetResult(e.Result); }; service.Completed += callback; service.RunAsync(parameter); return tcs.Task; }

Esto también resolverá la posible fuga de memoria que tenga cuando su servicio mantenga referencias a todos estos delegados.

Sin embargo, debe tener en cuenta que no puede tener varias de estas operaciones ejecutándose al mismo tiempo. Al menos no a menos que tenga una forma de hacer coincidir las solicitudes y las respuestas.

over 4 years ago · Santiago Trujillo Report

0

Parece que MyService generará el evento Completed más de una vez. esto hace que se llame a SetResult más de una vez, lo que provoca su error.

Tienes 3 opciones que veo. Cambie el evento Completed para que solo se genere una vez (parece extraño que pueda completar más de una vez), cambie SetResult a TrySetResult para que no arroje una excepción cuando intente configurarlo por segunda vez (esto introduce una pequeña pérdida de memoria como el evento aún se llama y la fuente de finalización aún intenta establecerse), o darse de baja del evento ( respuesta de i3arnon )

over 4 years ago · Santiago Trujillo Report

0

Una solución alternativa a la respuesta de i3arnon sería:

 public async static Task<string> ProcessAsync(MyService service, int parameter) { var tcs = new TaskCompletionSource<string>(); EventHandler<CustomEventArg> callback = (s, e) => tcs.SetResult(e.Result); try { contacts.Completed += callback; contacts.RunAsync(parameter); return await tcs.Task; } finally { contacts.Completed -= callback; } }

Sin embargo, esta solución tendrá una máquina de estado generada por el compilador. Utilizará más memoria y CPU.

over 4 years ago · Santiago Trujillo Report
Answer question
Find remote jobs

Discover the new way to find a job!

Top jobs
Top job categories
Business
Post vacancy Pricing Sales
Legal
Terms and conditions Privacy policy
© 2026 PeakU Inc. All Rights Reserved.
Andres GPT
Show me some job opportunities
There's an error!