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?