Interesting problem here. I have a class that deals with System.Data elements that was original written to use concrete classes as parameters. It was recently updated to use interfaces instead so that we had greater compatibility with other databases.
My problem comes from the following method, and its updated counterpart:
Old:
public bool Transact(Func<DbTransaction, bool> functionBlock)
{
... Stuff ...
}
New:
public bool NewTransact(Func<IDbTransaction, bool> functionBlock)
{
... Stuff ...
}
The old version results in a DbTransaction
object being spit out that we can send to other methods in our projects, while the newer one gives back an IDbTransaction
. I named the updated version NewTransaction so that the older projects out there will not be broken should the end up sitting alongside the newer library (DLL Hell and whatnot).
I can make rename NewTransact to Transact and it will compile just fine, but I don't see a way to call one over the other. My current solution will work just fine, but eventually NewTransact will no longer be "new". At that time, removing the old method and changing the name on the new one will just cause the problem to show up again.
My question is: Is there a way to pick which specific method is called if they're both the same name?
I'm guessing there isn't, but I figured this would make a good question.
EDIT: The key component to this question is maintaining backwards compatibility. Any answer that would require updating old software to continue to function is irrelevant. If I wanted to go back and update other projects I would simply do that in the first place rather than creating these overloads.
Here is a sample that works and how you can force which will be called:
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; }
}
As someone else stated, the compiler will determine which function is being called. But in my example, Foo is also an IFoo so I assume this is the crux of the issue.
Output:
Transact(
Func<Foo, bool> funcBlock
)
isFoo: TrueTransact(
Func<IFoo, bool> funcBlock
)
isIFoo: True
Update per comment
To summarize and put this in scope of the question, use one of the following to determine which function your code should call:
((DbTransaction transaction) => ...)
... or
((IDbTransaction transaction) => ...)