Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Async functionality missing from the IDbCommand interface

Is this a reasonable way to add async functionality to the IDbCommand interface?

public async static Task<IDataReader> ExecuteReaderAsync(this IDbCommand self) {
    DbCommand dbCommand = self as DbCommand;
    if (dbCommand != null) {
        return await dbCommand.ExecuteReaderAsync().ContinueWith(task => (IDataReader)task.Result);
    } else {
        return await Task.Run(() => self.ExecuteReader());
    }
}

Specifically, I'm not entirely sure what the effects of using "ContinueWith" to fake the covariance of "Task".

Also, in the unlikely case that the incoming "self" instance does not inherit from DbCommand, will a thread pool thread be consumed and blocked during the execution of "self.ExecuteReader()"?

Here's a link to my complete implementation of IDb extensions for async support.

Thank you

like image 459
Jean Lord Avatar asked Mar 18 '23 08:03

Jean Lord


1 Answers

Just because it is cleaner, I would take advantage of the fact that you’re using async and await to do away with the cast in the ContinueWith(). await evaluates to an object of type TResult when used on a Task<TResult>. I was going to suggest the syntax return (IDataReader)await dbCommand.ExecuteReaderAsync();, but then I remembered that the compiler already knows that DbDataReader is IDataReader. Tested in VS 2013 and VS 2015 Preview (not sure what you’re targeting, but I assume all C# compilers that support await should work with this):

public async static Task<IDataReader> ExecuteReaderAsync(this IDbCommand self) {
    DbCommand dbCommand = self as DbCommand;
    if (dbCommand != null) {
        return await dbCommand.ExecuteReaderAsync();
    } else {
        return await Task.Run(() => self.ExecuteReader());
    }
}

Now you’re using await to its fuller potential and saving a few bytes of code ;-).

The biggest concern with this implementation is, of course, the runtime type testing in self as DbCommand. In my opinion, DbCommand should be used instead of IDbCommand. This would let you remove the runtime cast. However, you probably wouldn’t have written this library if there was no problem with switching everything from IDbCommand to DbCommand and the runtime type check is probably performant enough.

Visual Studio 2017 Syntax

With newer versions of C#, you can use the is keyword instead of as to write more concise code:

public async static Task<IDataReader> ExecuteReaderAsync(this IDbCommand self) {
    if (self is DbCommand dbCommand) {
        return await dbCommand.ExecuteReaderAsync();
    } else {
        return await Task.Run(() => self.ExecuteReader());
    }
}
like image 172
binki Avatar answered Apr 02 '23 11:04

binki