Necesito llamar a un async
método en un catch
bloque antes de lanzar nuevamente la excepción (con su seguimiento de pila) como este:
try
{
// Do something
}
catch
{
// <- Clean things here with async methods
throw;
}
Pero desafortunadamente no puedes usarlo await
en un bloque catch
o finally
. Aprendí que es porque el compilador no tiene forma de retroceder en un catch
bloque para ejecutar lo que está después de tu await
instrucción o algo así ...
Traté de usar Task.Wait()
para reemplazar await
y obtuve un punto muerto. Busqué en la Web cómo podía evitarlo y encontré este sitio .
Como no puedo cambiar los async
métodos ni sé si se usan ConfigureAwait(false)
, creé estos métodos que toman un Func<Task>
método que inicia un método asíncrono una vez que estamos en un hilo diferente (para evitar un punto muerto) y espera a que se complete:
public static void AwaitTaskSync(Func<Task> action)
{
Task.Run(async () => await action().ConfigureAwait(false)).Wait();
}
public static TResult AwaitTaskSync<TResult>(Func<Task<TResult>> action)
{
return Task.Run(async () => await action().ConfigureAwait(false)).Result;
}
public static void AwaitSync(Func<IAsyncAction> action)
{
AwaitTaskSync(() => action().AsTask());
}
public static TResult AwaitSync<TResult>(Func<IAsyncOperation<TResult>> action)
{
return AwaitTaskSync(() => action().AsTask());
}
Entonces mi pregunta es: ¿Crees que este código está bien?
Por supuesto, si tiene algunas mejoras o conoce un enfoque mejor, ¡lo escucho! :)
fuente
await
en un bloque de captura está realmente permitido desde C # 6.0 (vea mi respuesta a continuación)Respuestas:
Puede mover la lógica fuera del
catch
bloque y volver a lanzar la excepción después, si es necesario, usandoExceptionDispatchInfo
.De esta forma, cuando la persona que llama inspecciona la
StackTrace
propiedad de la excepción , aún registra dóndeTaskThatFails
se lanzó.fuente
ExceptionDispatchInfo
lugar deException
(como en la respuesta de Stephen Cleary)?Exception
, ¿perderás todo el anteriorStackTrace
?Debe saber que desde C # 6.0, es posible usar
await
incatch
yfinally
blocks, por lo que de hecho podría hacer esto:Las nuevas características de C # 6.0, incluida la que acabo de mencionar, se enumeran aquí o en un video aquí .
fuente
Si necesita utilizar
async
controladores de errores, le recomiendo algo como esto:El problema con el bloqueo sincrónico en el
async
código (independientemente del hilo en el que se esté ejecutando) es que está bloqueando sincrónicamente. En la mayoría de los escenarios, es mejor usarawait
.Actualización: ya que necesita volver a lanzar, puede usar
ExceptionDispatchInfo
.fuente
throw exception;
en laif
declaración, se perderá el seguimiento de la pila.Se extrajeron gran respuesta de hvd a la siguiente clase de utilidad reutilizables en nuestro proyecto:
Uno lo usaría de la siguiente manera:
Siéntase libre de mejorar el nombre, lo mantuvimos intencionalmente detallado. Tenga en cuenta que no es necesario capturar el contexto dentro del contenedor, ya que ya está capturado en el sitio de la llamada, por lo tanto
ConfigureAwait(false)
.fuente