如何处置任务使用的托管资源? (不是.NET 4.5)

时间:2014-04-26 22:19:41

标签: c# .net-4.0 task-parallel-library

我正在处理的特定场景涉及与任务一起使用的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);

从表面上看,这似乎是一种更好的方法,虽然我不知道为什么会这样。我也觉得这不会引发第二个问题,但我并不完全确定。此外,在这种情况下,我完全不知道如何将一个异常传播给调用者。实际上,我甚至不确定如何识别是否发生了异常。

提前感谢您的帮助。

1 个答案:

答案 0 :(得分:0)

如果您无法使用async/await,如果IDisposable个对象在多个Task.ContinueWith回调中共享,确保IEnumerator个对象得到正确处置可能会非常繁琐。

为了实现这一点,您可以利用另一种编译器生成的状态机代码:try/finally方法。这将允许具有伪线性代码流并像往常一样使用usingstatic 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}}