I have a simple Money
type with an implicit cast from decimal
:
struct Money
{
decimal innerValue;
public static implicit operator Money(decimal value)
{
return new Money { innerValue = value };
}
public static explicit operator decimal(Money value)
{
return value.innerValue;
}
public static Money Parse(string s)
{
return decimal.Parse(s);
}
}
And I defined a Sum()
overload to operate on those values:
static class MoneyExtensions
{
public static Money Sum<TSource>(this IEnumerable<TSource> source, Func<TSource, Money> selector)
{
return source.Select(x => (decimal)selector(x)).Sum();
}
}
What I didn't expect was for this extension method to interfere with the existing Sum()
extension methods:
var source = new[] { "2" };
Money thisWorks = source.Sum(x => Money.Parse(x));
int thisWorksToo = source.Sum(new Func<string, int>(x => int.Parse(x)));
int thisDoesNot = source.Sum(x => int.Parse(x));
The error is "Cannot implicitly convert type 'Money' to 'int'. An explicit conversion exists (are you missing a cast?)". Is it correct that the compiler favors int => decimal => Money
implicit conversions over resolving an overload that's an exact match?
From the C# 4.0 Specification, section 7.6.5.2:
Probably, this is causing your Money Sum extension method to take precedence over the ones from Linq - that's why you don't get an "ambiguous method call" error.
Following on from Rob Siklos's research, (please vote up the research) Putting the extension in a seperate namespace fixes this problem. I seem to recall this as one of the guidelines for extensions.
It's because you are explicitly declaring
thisDoesNot
as typeint
. If you use implicit declaration, it works fine:From the specification: