使用接口版本重载方法的委托参数

时间:2013-11-19 21:34:18

标签: c# interface delegates backwards-compatibility

这里有趣的问题。我有一个类处理System.Data元素,这些元素是原始编写的,使用具体类作为参数。它最近更新为使用接口,以便我们与其他数据库具有更好的兼容性。

我的问题来自以下方法及其更新版本:

旧:

public bool Transact(Func<DbTransaction, bool> functionBlock)
{
    ... Stuff ...
}

新:

public bool NewTransact(Func<IDbTransaction, bool> functionBlock)
{
    ... Stuff ...
}

旧版本导致DbTransaction对象被吐出,我们可以发送到我们项目中的其他方法,而较新的对象返回IDbTransaction。我将更新后的版本命名为 NewTransaction ,这样如果最终的新项目(DLL Hell和诸如此类的东西)坐在一起,那么旧的项目就不会被破坏。

我可以将 NewTransact 重命名为 Transact ,它会编译得很好,但是我没有办法调用另一个。我目前的解决方案可以正常工作,但最终 NewTransact 将不再是“新的”。那时,删除旧方法并更改新方法的名称只会导致问题再次出现。

我的问题是:如果它们的名字相同,有没有办法选择调用哪种特定方法?

我猜不会,但我认为这会成为一个很好的问题。

编辑:此问题的关键组成部分是保持向后兼容性。任何需要更新旧软件以继续运行的答案都是无关紧要的。如果我想回去更新其他项目,我会首先简单地做,而不是创建这些重载。

3 个答案:

答案 0 :(得分:1)

这是一个有效的示例,以及如何强制调用哪个:

      private static readonly Program p = new Program();

      private Foo foo;

      static void Main(string[] args) {
         p.foo = new Foo();
         p.foo.IsFoo = true;
         p.foo.IsIFoo = true;

         // uses Transact(Func<Foo, bool> funcBlock)
         var isFoo = p.Transact(f => f.IsFoo == true);
         Console.WriteLine("isFoo: {0}", isFoo);

         //  this is ambiguous
         //var isIFoo = p.Transact(f=> (f as IFoo).IsIFoo == true);

         // this works
         var isIFoo = p.Transact((IFoo f) => f.IsIFoo == true);
         Console.WriteLine("isIFoo: {0}", isIFoo);


         Console.ReadLine();
      }

      bool Transact(Func<Foo, bool> funcBlock) {
         Console.WriteLine("Transact(Func<Foo, bool> funcBlock)");

         return (funcBlock(p.foo));
      }

      bool Transact(Func<IFoo, bool> funcBlock) {
         Console.WriteLine("Transact(Func<IFoo, bool> funcBlock)");

         return (funcBlock(p.foo));
      }
   }

   class Foo : IFoo {

      public bool IsFoo {
         get;
         set;
      }

      public bool IsIFoo {
         get;
         set;
      }

   }

   interface IFoo {

      bool IsIFoo { get; set; }
   }

正如其他人所说,编译器将确定调用哪个函数。但在我的例子中,Foo也是一个IFoo,所以我认为这是问题的关键。

输出:

  

的Transact(Func<Foo, bool> funcBlock
  isFoo:是的

     

的Transact(Func<IFoo, bool> funcBlock
  isIFoo:是的

每次评论

更新
要总结并将其置于问题的范围内,请使用以下方法之一来确定代码应调用的函数:

((DbTransaction transaction) => ...)

......或

((IDbTransaction transaction) => ...)

答案 1 :(得分:0)

将调用编译器根据参数类型选择的方法。

例如:

    Func<DbTransaction, bool> f1 = dbt => false;
    Func<IDbTransaction, bool> f2 = idbt => false;

    // Possible from .NET 4.0 since type parameter T of Func<in T, out TResult> is contravariant.
    var f3 = (Func<DbTransaction, bool>)f2;

    // Calls Transact with Func<DbTransaction, bool> parameter.
    Transact(f1);

    // Calls Transact with Func<IDbTransaction, bool> parameter.
    Transact(f2);

    // Calls Transact with Func<DbTransaction, bool> parameter.
    Transact(f3);

答案 2 :(得分:0)

也许将两者都重命名为Transact,然后在新代码中重命名尝试获取如下所示的方法:

MethodInfo transact = YourType.GetMethod("Transact",new Type[] {typeof(Func<IDbTransaction, bool>)});

然后叫它:

bool returnVal = transact.Invoke(callingObject, new object[]{yourArgumentHere});

这个 应该给你一种方法来调用指定的方法,而旧的代码仍然会使用Transact(Func<DbTransaction, bool> functionBlock)作为最接近提供的参数的实现。