3

.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
}

これを機能させるために私が見つけた唯一の方法は、この共有コードを使用して Visual Studio ソリューションを変更するすべての人のためのものです。

これは起こらないでしょう。機能する必要があります。そうしないと、まったく使用されません。

ソリューションが以前のバージョンの .NET Framework を対象としている場合、機能しないコードを定義する方法はありますか?

言い換えれば、これがコンパイルされた場合、それは素晴らしいことです:

public DbDataAdapter CreateDataAdapter(DbConnection conn)
{
   if (System.Runtime.Version >= 45)
      return DbProviderFactories.GetFactor(connection).CreateDataAdapter();
   else
   {
      //...snip the hack...
   }
}

ただし、対象のフレームワークが低すぎるとコンパイルされません。

4

3 に答える 3

4

最小限のコンパイル時間のセットアップでこれを機能させることが優先される場合は、チェックをランタイムに移動し、リフレクションを使用してメソッドが使用可能かどうかを確認し、そうでない場合は回避策を使用します。これは、.NET 4.5 がインストールされたクライアントで実行されている .NET 4.0 をターゲットとするアプリケーションがより優れたアプローチを使用するという追加の利点です。

サンプル:

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();
}

このアプローチは、ブラウザー スニッフィングを実行する代わりに、機能が使用可能であることを確認する JavaScript の世界における現在のベスト プラクティスと非常によく似ています。対応する .NET には、リフレクションを使用する必要があるため、同じエレガンスがありません。dynamicただし、要件が受け入れられる場合は、コードをよりきれいにすることができます。

于 2013-09-30T15:22:27.860 に答える
0

コードが JIT されていない限り、存在しないメソッド/クラス/アセンブリを参照している可能性があります。JIT の最小単位は関数全体であるため、関数から欠落している可能性のあるメソッド/クラスを参照するコードを配置し、関数をいつ呼び出すかを動的に決定する必要があります。

public DbDataAdapter CreateDataAdapter(DbConnection conn)
{
   if (System.Runtime.Version >= 45)
   {
      return Hide45DependencyFromJit(connection);
   }
   else
   {
      //...snip the hack...
   }
}

private void Hide45DependencyFromJit(... connection)
{
      return DbProviderFactories.GetFactor(connection).CreateDataAdapter();
}

ノート:

  • 4/4.5 フレームワークに問題があるかどうかはわかりませんが、このアプローチは、他の「欠落している機能」の場合に役立ちました。
  • Ngen'ed の場合は機能しない可能性があります (不明)。
  • ターゲットフレームワークをより高く設定し、非常に注意して、新しいメソッドへの依存関係を誤って取得しないようにする必要があります。
于 2013-09-30T01:46:36.843 に答える