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 框架时,有没有办法定义掉非功能性代码?

换句话说,如果编译如下,那就太好了:

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

但是如果目标框架太低,它就不会编译。

4

3 回答 3

4

如果优先级是使用最少的编译时间设置来工作,那么我只需将检查移至运行时并使用反射来检查该方法是否可用,并在它不可用时使用解决方法。这是一个额外的好处,即在安装了 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 回答
1

此答案与标记的答案相同,但对于寻求不基于用户原始帖子场景的解决方案的其他人来说更容易消化。


使用反射来确定类是否存在。如果是,则动态创建并使用它,否则使用可以为该场景定义的解决方法类或代码。

这是我用于AggregateException仅 .Net 4 及更高版本的代码:

var aggregatException = Type.GetType("System.AggregateException");

if (aggregatException != null) // .Net 4 or greater
{
    throw ((Exception)Activator.CreateInstance(aggregatException, ps.Streams.Error.Select(err => err.Exception)));
}

// Else all other non .Net 4 or less versions
throw ps.Streams.Error.FirstOrDefault()?.Exception 
      ?? new Exception("Powershell Exception Encountered."); // Sanity check operation, should not hit.
于 2017-03-02T16:40:53.623 回答
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 回答