I have a function that would love to take advantage of the "correct" way to do something that was provided in .NET 4.5:
public DbDataAdapater CreateDataAdapter(DbConnection connection)
{
#IFDEF (NET45)
return DbProviderFactories.GetFactory(connection).CreateDataAdapter();
#ELSE
//We can't construct an adapter directly
//So let's run around the block 3 times, before potentially crashing
DbDataAdapter adapter;
if (connection is System.Data.SqlClient.SqlConnection)
return new System.Data.SqlClient.SqlDataAdapter();
if (connection is System.Data.OleDb.OleDbConnection)
return new System.Data.OleDb.OleDbDataAdapter();
if (connection is System.Data.Odbc.OdbcConnection)
return new System.Data.Odbc.OdbcDataAdapter();
//Add more DbConnection kinds as they become invented
if (connection is SqlCeConnection)
return new SqlCeDataAdapter();
if (connection is MySqlConnection)
return new MySqlDataAdapter();
if (connection is DB2Connection)
return new DB2DataAdapter();
throw new Exception("[CreateDataAdapter] Unknown DbConnection type: " + connection.GetType().FullName);
#END
}
The only way i've been able to find to make this work is for everyone who uses this shared code to alter their Visual Studio solution.
Which not going to happen; it has to just work, or it's not going to be used at all.
Is there a ways to define away non-functional code when the solution targets earlier versions of the .NET framework?
In other words, it would be great if this compiled:
public DbDataAdapter CreateDataAdapter(DbConnection conn)
{
if (System.Runtime.Version >= 45)
return DbProviderFactories.GetFactor(connection).CreateDataAdapter();
else
{
//...snip the hack...
}
}
But it doesn't compile if the targeted framework is too low.
If the priority is to have this working with minimal compile time setup then I would just move the check to runtime and use reflection to check if the method is available and use the workaround when its not. This as the added benefit that an application targeting .NET 4.0 running in a client with 4.5 installed will use the better approach.
Sample:
static Func<DbConnection, DbProviderFactory> GetFactoryDelegate;
private static void Main() {
Console.WriteLine(GetFactory(new SqlConnection()).CreateDataAdapter());
}
private static DbProviderFactory GetFactory(DbConnection connection) {
if (GetFactoryDelegate == null) {
var frameworkGetFactoryMethod = typeof (DbProviderFactories).GetMethod(
"GetFactory", BindingFlags.Static | BindingFlags.Public,
null, new[] { typeof (DbConnection) }, null);
if (frameworkGetFactoryMethod != null) {
GetFactoryDelegate = (Func<DbConnection, DbProviderFactory>)
Delegate.CreateDelegate(
typeof(Func<DbConnection, DbProviderFactory>),
frameworkGetFactoryMethod);
}
else { GetFactoryDelegate = GetFactoryThroughWorkaround; }
}
return GetFactoryDelegate(connection);
}
private static DbProviderFactory GetFactoryThroughWorkaround(
DbConnection connection) {
if (connection is SqlConnection)
return SqlClientFactory.Instance;
// ... Remaining cases
throw new NotSupportedException();
}
This approach is much similar to what is current best practice in the JavaScript world of checking that a feature is available instead of performing browser sniffing. The .NET counterpart does not have the same elegance due to requiring the use of reflection. However, the code could be made prettier if the requirement for dynamic is acceptable.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With