Pregunta

Este ejemplo "falla":

static async void Main(string[] args)
{
    try
    {
        await TaskEx.Run(() => { throw new Exception("failure"); });
    }
    catch (Exception)
    {
        throw new Exception("success");
    }
}

Es decir, la excepción con el texto "falla" burbujea.

Luego probé esta solución:

static async void Main(string[] args)
{
    try
    {
        await SafeRun(() => { throw new Exception("failure"); });
    }
    catch (Exception)
    {
        throw new Exception("success");
    }
}

static async Task SafeRun(Action action)
{
    var ex = default(Exception);
    await TaskEx.Run(() =>
    {
        try
        {
            action();
        }
        catch (Exception _)
        {
            ex = _;
        }
    });
    if (ex != default(Exception))
        throw ex;
}

Eso tampoco ayudó.

Supongo que mi instalación de actualización de ASYNC CTP podría ser manejada.

Si este código funciona como espero ("éxito" burbujee, no "falla"), o no se supone que esto "se supone que funcione de esa manera. Y si no, ¿cómo trabajarías?

¿Fue útil?

Solución

El comportamiento que está viendo es probablemente un error de caso de borde o incluso puede ser correcto, aunque no intuitivo. Normalmente, cuando invoca un método de asíncrono sincrónicamente, envuelve una tarea para ejecutar y, dado que no hay nadie que esté esperando la tarea para terminar, la excepción nunca llega al hilo principal. Si llamara a Main directamente, tendría éxito, pero su tiempo de ejecución vería una excepción de "éxito" en otro hilo.

Dado que Main es el punto de entrada de su aplicación, se invoca sincrónicamente y probablemente ya que el punto de entrada no desencadena el comportamiento de envoltura de tareas, por lo que la espera no se ejecuta correctamente y el taskex.run arroja su propio hilo, que aparece El tiempo de ejecución como una excepción se arroja en otro hilo.

Si tuviera que ejecutar el principal como un async método, es decir, devolver un Task (Desde un async que regresa void Solo se puede llamar realmente a través de await) Y bloquearlo de su contexto principal sincrónico, obtendría el comportamiento apropiado como lo ilustra la siguiente prueba:

static async Task Main() {
    try {
        await TaskEx.Run(() => { throw new Exception("failure"); });
    } catch(Exception) {
        throw new Exception("success");
    }
}

static async Task Main2() {
    await Main();
}

[Test]
public void CallViaAwait() {
    var t = Main2();
    try {
        t.Wait();
        Assert.Fail("didn't throw");
    } catch(AggregateException e) {
        Assert.AreEqual("success",e.InnerException.Message);
    }
    }


[Test]
public void CallDirectly() {
    var t = Main();
    try {
        t.Wait();
        Assert.Fail("didn't throw");
    } catch(AggregateException e) {
        Assert.AreEqual("success", e.InnerException.Message);
    }
}

Es decir, las fallas de la tarea con un AggregateException que contiene el éxito Excepción como es una excepción interna.

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