"David Browne" <davidbaxterbrowne no potted meat@hotmail.com> wrote in =
message news:ufyK9aLRHHA.4632@TK2MSFTNGP04.phx.gbl...
[quoted text, click to view] >=20
>=20
> "Robert Simpson" <rmsimpson@noemail.noemail> wrote in message=20
> news:OhlZURKRHHA.3592@TK2MSFTNGP06.phx.gbl...
>> "David Browne" <davidbaxterbrowne no potted meat@hotmail.com> wrote =
in=20
>> message news:u$cy2NJRHHA.3316@TK2MSFTNGP02.phx.gbl...
>>>
>>>
>>> "Robert Simpson" <rmsimpson@noemail.noemail> wrote in message=20
>>> news:#OpN8#HRHHA.2172@TK2MSFTNGP04.phx.gbl...
>>>> "Jed Ozone" <jed ozone@yahoo.com> wrote in message=20
>>>> news:uKWtE1HRHHA.4692@TK2MSFTNGP05.phx.gbl...
>>>>
>>>> The default DbCommand.ExecuteReader() functions call the protected=20
>>>> ExecuteDbDataReader() function, which is what you'll be =
implementing in=20
>>>> your derived class.
>>>>
>>>> If you want to be complete however, you should use the "new" =
keyword and=20
>>>> override the two ExecuteReader() functions as well so they return =
your=20
>>>> type-specific data reader.
>>>
>>> Why would you want to do that? Then you'll run different code =
depending=20
>>> on the type the client binds to. You definitely wouldn't want =
different=20
>>> behavior in these cases, so why hide the method?
>>
>> No you won't. Please explain how the behaviors are different ...
>>
>=20
> The two aren't different, if you code them to do the exact same thing. =
But=20
> why would you want to hide a method with an implementation that does =
the=20
> exact same thing as the overriden method?
The point is, they do not do the same thing. One returns a =
DbDataReader, and the other returns a SQLiteDataReader. While you can =
implicitly cast a SQLiteDataReader to a DbDataReader, you cannot =
implicitly cast in the other direction and hence the different codepaths =
are distinct in purpose.
[quoted text, click to view] > How do you know that DbCommand.ExecuteReader doesn't do anything other =
than=20
> call the protected method? What if this changes in the future?
It cannot and will not change. DbCommand.ExecuteReader() has no =
knowledge of implementation, and leaves implementation up to the =
provider via the ExecuteDbDataReader(). Its behavior is documented and =
will not change. If in the future Microsoft determines that additional =
functionality is needed, they will create a new function for it and will =
not break the millions of deployed apps already out in the wild.
=20
[quoted text, click to view] >> Scenario 1: User calls DbCommand.ExecuteReader(...)
>> Result: The base DbCommand function calls the overridden=20
>> ExecuteDbDataReader() which in turn calls my "new" ExecuteReader() =
and=20
>> returns a type-specific SQLiteDataReader.
>>
>> Scenario 2: User calls SQLiteCommand.ExecuteReader(...)
>> Result: The "new" ExecuteReader function returns a type-specific=20
>> SQLiteDataReader.
>>
>> Both scenarios drill down to my "new" implementation of =
ExecuteReader()=20
>> which returns a type-specific DataReader for my object. Scenario 1 =
has 1=20
>> extra function call, and the base DbCommand function casts the =
resulting=20
>> object down to a DbDataReader, but that's what its supposed to do =
anyway.
>>
>=20
> So you have two different code paths to maintain that both do exactly =
the=20
> same thing.
There is one code path, and they do not do the same thing. All paths =
converge at the new type-specific ExecuteReader(CommandBehavior) =
function. There is no duplication of anything.
Lets start by examining two sample usages, one with the built-in =
Microsoft Sql Server provider, and the other with mine:
// SqlClient version
using (SQCommand cmd =3D sqlcnn.CreateCommand())
{
cmd.CommandText =3D "SELECT GetDate()";
using(SqlDataReader reader =3D cmd.ExecuteReader())
{
// etc etc
}
}
// SQLite version
using (SQLiteCommand cmd =3D sqlitecnn.CreateCommand())
{
cmd.CommandText =3D "SELECT * FROM sqlite_master";
using(SQLiteDataReader reader =3D cmd.ExecuteReader())
{
// etc etc
}
}
The above code samples are nearly identical, and are common usage =
scenarios that happen frequently. If I were to remove the "new" =
ExecuteReader functions in my implementation of SQLiteCommand, then the =
above code would no longer compile against my provider. The reason it =
would no longer compile is because there would be no version of =
ExecuteReader() that returns a SQLiteDataReader and the call to =
cmd.ExecuteReader() would require an explicit up-cast.
Leaving out the "new" ExecuteReader() functions would be inconsistent =
with the way the other ADO.NET providers behave. The rule seems to be, =
"be specific when being specific, and be generic when being generic."
In either case, the code below will compile in any circumstance, but =
using the "be generic when being generic" rule:
using (DbCommand cmd =3D sqlitecnn.CreateCommand())
{
cmd.CommandText =3D "SELECT * FROM sqlite_master";
using (DbDataReader reader =3D cmd.ExecuteReader())
{
// etc etc
}
}
If you'd like more examples, look at the following:
SqlConnection.CreateCommand() vs. DbConnection.CreateCommand()
SqlCommand.CreateParameter() vs. DbCommand.CreateParameter()
In each of these cases as well, the SqlConnection and SqlCommand objects =
have overridden using "new" the CreateXXX() functions in addition to =
overriding the virtual base implementations (CreateDbParameter and =
CreateDbCommand) so as to return a generic or type-specific object =
without forcing the user to explicitly upcast.
It's merely a matter of convenience to the user so they can be as =
specific or as generic as they like without forcing them to explicitly =
cast the return values.