我正在处理的特定场景涉及与任务一起使用的SqlConnection和SqlCommand。我想知道在任务完成时如何最好地处理SqlConnection和SqlCommand。可以说我有这两个对象:
SqlConnection connection = new SqlConnection(base._ConnectionString);
SqlCommand command = new SqlCommand("SomeProcedure", connection);
我正在考虑两种不同的处理方法。
首先是使用延续来清理所有内容。
return Task.Factory
.FromAsync<int>(
beginMethod: command.BeginExecuteNonQuery,
endMethod: command.EndExecuteNonQuery,
state: null)
.ContinueWith(a =>
{
if (command != null)
{
command.Dispose();
}
if (connection != null)
{
connection.Dispose();
}
// Need to propagate the exception too if one occurred.
a.Wait();
});
我在这里担心的是,我认为这会为了处理延续而旋转另一个线程?我使用FromAsync方法的全部原因是试图避免这样做。此外,正如您在此示例中所看到的,我有点不确定如何最好地确保任何异常都返回给调用者。我正在尝试这个技巧,等待强制继续任务重新抛出异常,但感觉不太正确。
我正在研究的第二种方法是使用lambda作为'endMethod'参数:
return Task.Factory
.FromAsync<int>(
beginMethod: command.BeginExecuteNonQuery,
endMethod: (asyncResult =>
{
int test = command.EndExecuteNonQuery(asyncResult);
command.Dispose();
connection.Dispose();
return test;
}),
state: null);
从表面上看,这似乎是一种更好的方法,虽然我不知道为什么会这样。我也觉得这不会引发第二个问题,但我并不完全确定。此外,在这种情况下,我完全不知道如何将一个异常传播给调用者。实际上,我甚至不确定如何识别是否发生了异常。
提前感谢您的帮助。
答案 0 :(得分:0)
如果您无法使用async/await
,如果IDisposable
个对象在多个Task.ContinueWith
回调中共享,确保IEnumerator
个对象得到正确处置可能会非常繁琐。
为了实现这一点,您可以利用另一种编译器生成的状态机代码:try/finally
方法。这将允许具有伪线性代码流并像往常一样使用using
和static IEnumerator<Task> GetSequenceOfTasks()
{
using (SqlConnection connection = new SqlConnection(base._ConnectionString))
{
yield return TestConnectionAsync(connection);
using (SqlCommand command = new SqlCommand("SomeProcedure", connection))
{
yield return ExecuteCommandAsync(command);
}
}
}
// ...
// task will complete when ExecuteCommandAsync has completed
var task = GetSequenceOfTasks().RunAsync();
// ...
// execute a sequence of tasks, propagate exceptions and cancellation (if any)
public static class TaskExt
{
public static Task<object> RunAsync(this IEnumerator<Task> @this)
{
if (@this == null)
throw new ArgumentNullException();
var tcs = new TaskCompletionSource<object>();
Action<Task> nextStep = null;
nextStep = (previousTask) =>
{
try
{
if (previousTask.IsCanceled)
tcs.SetCanceled();
else if (previousTask.IsFaulted)
tcs.SetException(previousTask.Exception);
else
{
// move to the next task
if (@this.MoveNext())
{
@this.Current.ContinueWith(nextStep,
TaskContinuationOptions.ExecuteSynchronously);
}
else
tcs.SetResult(previousTask);
}
}
catch (Exception ex)
{
tcs.TrySetException(ex);
}
};
nextStep(Task.FromResult(Type.Missing));
return tcs.Task.ContinueWith(
completedTask => { @this.Dispose(); return completedTask; },
TaskContinuationOptions.ExecuteSynchronously).Unwrap();
}
}
语句。例如,以下内容基于Stephen Toub's Iterate
pattern:
{{1}}