【问题标题】:Access property of generic type not defined in interface using dynamic通用类型的访问属性未在使用动态的接口中定义
【发布时间】:2011-11-11 00:50:35
【问题描述】:

我不得不修改大量代码来为一堆表适配器设置 SqlCe 数据库连接。我想通过创建一个通用方法来包装每个表适配器的创建,从而避免所涉及的重复并最大限度地减少我错过更新表适配器的机会。不幸的是,表适配器不是从单个基类派生的,每个适配器都有自己的 Connection 属性。通过将新的表适配器分配给 dynamic 我可以编译它。这是一个好方法吗?在使用 dynamic 时我应该注意哪些陷阱?

protected void TableAdapter<T>(Action<T> action) where T : IDisposable, new()
{
    using (var connection = new SqlCeConnection(ConnectionString))
    using (dynamic tableAdapter = new T())
    {
        tableAdapter.Connection = connection;
        action(tableAdapter);
    }
}

【问题讨论】:

    标签: c# generics dynamic


    【解决方案1】:

    不,没有陷阱。我认为您正在交换编译器检查以提高可读性。如果其他人使用错误,运行时错误将很明显Connection 成员不存在。

    就我个人而言,我还会将强制转换添加到动作的参数中,因为那里的动态调用不应该是必要的。但我认为这是一个可选的选择,因为性能提升可能可以忽略不计,无论哪种方式,它都会起作用,我的个人风格是将动态使用的范围限制为有目的的。

    protected void TableAdapter<T>(Action<T> action) where T : IDisposable, new()
    {
        using (var connection = new SqlCeConnection(ConnectionString))
        using (dynamic tableAdapter = new T())
        {
            tableAdapter.Connection = connection;
            action((T)tableAdapter);
        }
    }
    

    【讨论】:

      【解决方案2】:

      这可行,但对于 C# 来说有点不正统。这是一种为编译时安全而牺牲一点 DRY 的替代方法:

      protected void TableAdapter<T>(Action<T, SqlCeConnection> action) where T : IDisposable, new()
      {
          using (var connection = new SqlCeConnection(ConnectionString))
          using (var tableAdapter = new T())
          {
              action(tableAdapter, connection);
          }
      }
      

      现在您的操作将需要设置 Connection 以及其他任何操作,但编译器会验证访问权限并且您不会受到动态包装器的性能损失。

      【讨论】:

      • 谢谢 Dan,是的,我考虑过这种方法,但我认为我更有可能忘记在操作中设置连接,而不是针对表适配器以外的其他对象调用 TableAdapter。
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2012-11-17
      • 2014-06-11
      • 2014-05-21
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多