dko dko - 4 months ago 29
Vb.net Question

How come sqlconnection.createCommand overrides return type of IDBConnection.CreateCommand?

I'm creating a Data Access factory class. I have a base DataAccess class that returns an IDBConnection in GetConnection(). In the SQLDataAccess class it basically returns new SQLConnection(). What I'm wondering is how to override the return type to be a specific SQLConnection. I understand you can't change the method signature as discussed in override property with a derived type. But they do this in .net with the DBConnection.CreateCommand() DBConnection returns a DBCommand and SQLConnection returns a SQLCommand by definition. How are they doing this?

Answer

As far as how SqlConnection and others that derive from DbConnection do it they have a new signature that hides the one on DbConnection. Here is the partial code for DbConnection and SqlConnection.

public class abstract DbConnection {
    // ...
    public DbCommand CreateCommand()
    {
      return this.CreateDbCommand();
    }
    // ...
}

public class SqlConnection : DbConnection {
    // ...
    public SqlCommand CreateCommand()
    {
      return new SqlCommand((string) null, this);
    }
    // ...
}

You can use generics to accomplish this. There are other ways to do this though as it has been thought out before and there is more to it than just this as database implementations handle various items differently like placeholders for parameters, parameter types, functions that might exist in one implementation but not another, so your queries might have to vary too depending on the implementation. At first glance (we are obviously not getting the whole story here) this seems like reinventing the wheel so it might be better to research ORMs that abstract much of this for you.

public interface IDataAccess<TConnection, TCommand> where TConnection : IDbConnection where TCommand : IDbCommand
{
    TConnection GetConnection();
    TCommand CreateCommand(TConnection connection);
}

public class SQLDataAccess : IDataAccess<SqlConnection, SqlCommand>
{
    public SqlConnection GetConnection()
    {
        return new SqlConnection("");
    }

    public SqlCommand CreateCommand(SqlConnection connection)
    {
        return connection.CreateCommand();
    }
}

If you do not care about the specific implementation you are working with then I recommend you work with interfaces and forget the generics. Example:

public interface IDataAccess
{
    IDbConnection GetConnection();
    IDbCommand CreateCommand(IDbConnection connection);
}

public class SQLDataAccess : IDataAccess
{
    public IDbConnection GetConnection()
    {
        return new SqlConnection("");
    }

    public IDbCommand CreateCommand(IDbConnection connection)
    {
        return connection.CreateCommand();
    }
}