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)代码>