Empresas
Empregos
  • Sobre nós
  • Soluções
    • Publicação de vagas
      Publique sua vaga e receba candidatos qualificados em 48h.
    • Avaliações de candidatos
      Mais de 500 testes técnicos e psicológicos, mais anti-fraude.
    • Headhunting
      Busca executiva personalizada do início ao fim.
    • Folha de Pagamento + EOR
      Dispersão de folha e EOR em mais de 15 países da LATAM.
  • Preços
  • Empregos

0

342
Visualizações
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 Respostas
Responde à pergunta

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 Relatório

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 Relatório

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 Relatório
Responde à pergunta
Encontrar trabalhos remotos

Descubra a nova forma de encontrar um emprego!

melhores empregos
Principais categorias de trabalho
Empresas
Postar vaga Preços Comercial
Jurídico
Termos e Condições Política de privacidade
© 2026 PeakU Inc. All Rights Reserved.
Andres GPT
Recomende algumas ofertas para mim
Preciso de ajuda