Should I wrap a task in another task or should I just return the created task?
.net, .net-4.0, ado.net, c#, task-parallel-library
Solution
Your #3 is the best. The first two introduce complication for no reason.
1 potentially adds another thread purely to run `CheckIfSqlCommand()` and `PrepareExecuteReader()` asynchronously. This may be what you wanted, but they don't sound like commands that are going to take a long time.
2 references `.Result` of the task, which will block until the task is complete, so defeats the whole purpose of using tasks.
Problem
I'm building a .NET 4.0 application that uses ADO.NET, so I cannot use async/await. I don't want a solution for that, but I do want to know what of the following implementations is best and why. My unit tests pass for all three implementations, but I want to know the difference between these three. #1 Nesting tasks In my first implementation I wrap a task in another task. I think spinning up two tasks is bad for performance, but I'm not sure. ``` public virtual Task<IDataReader> ExecuteReaderAsync(IDbCommand dbCommand, CancellationToken cancellationToken) { return Task.Factory.StartNew(() => { var sqlCommand = CheckIfSqlCommand(dbCommand); PrepareExecuteReader(dbCommand); return Task<IDataReader> .Factory .FromAsync(sqlCommand.BeginExecuteReader, sqlCommand.EndExecuteReader, null) .Result; }, cancellationToken); } ``` #2 Using TaskCompletionSource Then I tried wrapping the result in a `TaskCompletionSource` so I just have one task. ``` public virtual Task<IDataReader> ExecuteReaderAsync(IDbCommand dbCommand, CancellationToken cancellationToken) { var taskCompletionSource = new TaskCompletionSource<IDataReader>(); var sqlCommand = CheckIfSqlCommand(dbCommand); PrepareExecuteReader(dbCommand); var reader = Task<IDataReader> .Factory .FromAsync(sqlCommand.BeginExecuteReader, sqlCommand.EndExecuteReader, null) .Result; taskCompletionSource.SetResult(reader); return taskCompletionSource.Task; } ``` #3 returning Task directly My final solution is to directly return the task I created instead of wrapping it. ``` public virtual Task<IDataReader> ExecuteReaderAsync(IDbCommand dbCommand, CancellationToken cancellationToken) { var sqlCommand = CheckIfSqlCommand(dbCommand); PrepareExecuteReader(dbCommand); return Task<IDataReader> .Factory .FromAsync(sqlCommand.BeginExecuteReader, sqlCommand.EndExecuteReader, null); } ``` So basically my question is: What option should I use or is there a better way to do this?