Ralph
Ralph

Reputation: 897

TypeCast To Overcome Interface Limitation?

I'm using IDbCommand and IDbDataParameter interfaces for my SQL db logic but realized that I can't get sqlCommand.parameter["ID"].Value because of an interface restriction.

Is it good practice to type cast an interfaced object to overcome a limitation of an interface?

Example

using (IDbCommand SqlCmd = CommandProvider.GetSPCommand(conn))
{
    // setup sqlcmd with output paramter and executenonquery ...
    ID = Convert.ToInt32(((SqlCommand)SqlCmd).Parameters["ID"].Value);
 }

Upvotes: 1

Views: 72

Answers (2)

Andrew
Andrew

Reputation: 21

Bradley is correct and concise with his answer. I would also add that based on your code, accessing stored procedure parameters doesn't necessarily have to be factor that couples you to a specific implementation. One of my favorite tools to achieve database independent data access code is the wonderful magic of Dapper. Believe it or not, it's the data access library that runs Stack Overflow!

From their documentation, you can add and access parameters with this code:

var p = new DynamicParameters();
p.Add("@a", 11);
p.Add("@b", dbType: DbType.Int32, direction: ParameterDirection.Output);
p.Add("@c", dbType: DbType.Int32, direction: ParameterDirection.ReturnValue);

cnn.Execute("spMagicProc", p, commandType: CommandType.StoredProcedure); 

int b = p.Get<int>("@b");
int c = p.Get<int>("@c"); 

You could then keep coding against abstractions like IDbCommand, IDbConnection, etc. Dapper has a highly performant way of taking values from a database and easily converting them to C# types (which could potentially eliminate your need to type cast in a few areas).

Casting via hard-cast (using parentheses) or soft-casting, at least in my book, are both considered code smell (though I agree with Bradley - go soft if you must). Only in a few specific areas would one have an absolute need to do it. For a trivial app, feel free to take a full dependency on your database and be along your merry way. For any non-trivial enterprise app, taking a hard dependency on your database will eventually vendor-lock your application stack and put future refactoring at risk.

Upvotes: 0

BradleyDotNET
BradleyDotNET

Reputation: 61349

No, this is not good practice.

First, you shouldn't downcast unless absolutely necessary. If you need a value that is only provided by a interface implementation, start with that implementation. In your case, if CommandProvider.GetSPCommand returns a SqlCommand, then just do:

using (SqlCommand SqlCmd = CommandProvider.GetSPCommand(conn))
{
    // setup sqlcmd with output paramter and executenonquery ...
    ID = Convert.ToInt32(((SqlCommand)SqlCmd).Parameters["ID"].Value);
 }

If it doesn't do that, then you've run into the second thing you have wrong which is doing a cast before checking if it is safe. If the returned item wasn't a SqlCommand your code would throw an InvalidCastException. Instead, check with the as operator:

using (IDbCommand SqlCmd = CommandProvider.GetSPCommand(conn))
{
    SqlCommand fullSqlCommand = SqlCmd as SqlCommand;
    if (fullSqlCommand != null)
    {
       // setup sqlcmd with output paramter and executenonquery ...
       ID = Convert.ToInt32(fullSqlCommand.Parameters["ID"].Value);
    }
    else
    {
        //Some failsafe
    }
 }

Of course, only using the interface is the preferred option, but that can be difficult when, as in this case, you don't control it.

Upvotes: 3

Related Questions