C# “寻找一种优雅的出行方式”;不能在finally子句的正文中等待;

C# “寻找一种优雅的出行方式”;不能在finally子句的正文中等待;,c#,async-await,C#,Async Await,我有以下功能: private async Task DoSomething(NamespaceConnectionInfo nci) { var session = await m_sessionProvider.GetSessionAsync(nci); SomeLegacySynchronousCode(session); await m_sessionProvider.EndSessionAsync(session); } 其中EndSessionAsync记录

我有以下功能:

private async Task DoSomething(NamespaceConnectionInfo nci)
{
    var session = await m_sessionProvider.GetSessionAsync(nci);
    SomeLegacySynchronousCode(session);
    await m_sessionProvider.EndSessionAsync(session);
}
其中
EndSessionAsync
记录并接受任何异常(就像一个好的析构函数)

问题是
SomeLegacySynchronousCode
可能会引发异常,然后会话泄漏

我完全清楚为什么以下代码是非法的:

private async Task DoSomething(NamespaceConnectionInfo nci)
{
    var session = await m_sessionProvider.GetSessionAsync(nci);
    try
    {
        SomeLegacySynchronousCode(session);
    }
    finally
    {
        await m_sessionProvider.EndSessionAsync(session);
    }
}
因此,我正在寻找一个既正确又优雅的替代方案

变体I

private async Task DoSomething(NamespaceConnectionInfo nci)
{
    var session = await m_sessionProvider.GetSessionAsync(nci);
    Exception exc = null;
    try
    {
        SomeLegacySynchronousCode(session);
    }
    catch (Exception e)
    {
        exc = e;
    }
    await m_sessionProvider.EndSessionAsync(session);
    if (exc != null)
    {
        // Wrap to preserve the original stack trace.
        throw new AggregateException(exc);
    }
}
private Task DoSomething(NamespaceConnectionInfo nci)
{
    return m_sessionProvider.GetSessionAsync(nci).ContinueWith(t =>
    {
        Task result = null;
        try
        {
            SomeLegacySynchronousCode(t.Result);
        }
        finally
        {
            if (t.Exception == null)
            {
                result = m_sessionProvider.EndSessionAsync(t.Result);
            }
        }
        return result;
    }).Unwrap();
}
变体II

private async Task DoSomething(NamespaceConnectionInfo nci)
{
    var session = await m_sessionProvider.GetSessionAsync(nci);
    Exception exc = null;
    try
    {
        SomeLegacySynchronousCode(session);
    }
    catch (Exception e)
    {
        exc = e;
    }
    await m_sessionProvider.EndSessionAsync(session);
    if (exc != null)
    {
        // Wrap to preserve the original stack trace.
        throw new AggregateException(exc);
    }
}
private Task DoSomething(NamespaceConnectionInfo nci)
{
    return m_sessionProvider.GetSessionAsync(nci).ContinueWith(t =>
    {
        Task result = null;
        try
        {
            SomeLegacySynchronousCode(t.Result);
        }
        finally
        {
            if (t.Exception == null)
            {
                result = m_sessionProvider.EndSessionAsync(t.Result);
            }
        }
        return result;
    }).Unwrap();
}
两者都不如前面提到的非法异步/等待版本那么优雅

我希望改进我提出的两种变体,因为坦率地说,这两种变体都很丑陋

有什么想法吗?

似乎与您的变体1相似:

您可以将逻辑移到catch块之外,然后重新调用 如果需要,使用ExceptionDispatchInfo在之后执行异常

static async Task f()
{
    ExceptionDispatchInfo capturedException = null;
    try
    {
        await TaskThatFails();
    }
    catch (MyException ex)
    {
        capturedException = ExceptionDispatchInfo.Capture(ex);
    }

    if (capturedException != null)
    {
        await ExceptionHandler();

        capturedException.Throw();
    }
}
这样,当调用方检查异常的堆栈跟踪时 属性,它仍然记录抛出失败的内部任务的位置


没有回答这个问题。什么是异常处理程序?我可以在MSDN中看到的是
System.ServiceModel.Dispatcher
System.Reflection.Emit
名称空间。似乎都不相关。
ExceptionHandler()
只是异常处理逻辑的占位符。在您的情况下,它将是
m_sessionProvider.EndSessionAsync(session)