I created extension method:
public static class XDecimal
{
public static decimal Floor(
this decimal value,
int precision)
{
decimal step = (decimal)Math.Pow(10, precision);
return decimal.Floor(step * value) / step;
}
}
Now I try to use it:
(10.1234m).Floor(2)
But compiler says Member 'decimal.Floor(decimal)' cannot be accessed with an instance reference; qualify it with a type name instead
. I understand there is static decimal.Floor(decimal)
method. But it has different signature. Why compiler is unable to choose correct method?
The process of deciding on which method to call has lots of small details described in the C# language specification. The key point applicable to your scenario is that extension methods are considered for invocation only when the compiler cannot find a method to call among the methods of the receiving type itself (i.e. the
decimal
).Here is the relevant portion of the specification:
According to the above,
double.Floor(decimal)
is a valid candidate.In your case the set of candidate methods is not empty, so extension methods are not considered.
The signature of
decimal.Floor
isI'm no specialist in type inference, but I guess since there is a implicit conversion from
int
toDecimal
the compiler chooses this as the best fitting method.If you change your signature to
and call it like
it works. But of course a
double
as precision is somewhat strange.EDIT: A quote from Eric Lippert on the alogrithm:
Floor
is a method of the "receiving type" (Decimal
). On the why the C# developers implemented it like this I can make no statement.You have two good and correct answers here, but I understand that answers which simply quote the specification are not always that illuminating. Let me add some additional details.
You probably have a mental model of overload resolution that goes like this:
Though this is many people's mental model of overload resolution, regrettably it is subtly wrong.
The real model -- and I will ignore generic type inference issues here -- is as follows:
At this point we either have methods in the bucket or we do not. If we have any methods in the bucket at all then extension methods are not checked. This is the important bit right here. The model is not "if normal overload resolution produced an error then we check extension methods". The model is "if normal overload resolution produced no applicable methods whatsoever then we check extension methods".
If there are methods in the bucket then there is some more elimination of base class methods, and finally the best method is chosen based on how well the arguments match the parameters.
If this happens to pick a static method then C# will assume that you meant to use the type name and used an instance by mistake, not that you wish to search for an extension method. Overload resolution has already determined that there is an instance or static method whose parameters match the arguments you gave, and it is going to either pick one of them or give an error; it's not going to say "oh, you probably meant to call this wacky extension method that just happens to be in scope".
I understand that this is vexing from your perspective. You clearly wish the model to be "if overload resolution produces an error, fall back to extension methods". In your example that would be useful, but this behaviour produces bad outcomes in other scenarios. For example, suppose you have something like
The error given here is that it should be
string.Join
. It would be bizarre if the C# compiler said "oh,string.Join
is static. The user probably meant to use the extension method that does joins on sequences of characters, let me try that..." and then you got an error message saying that the sequence join operator -- which has nothing whatsoever to do with your code here -- doesn't have the right arguments.Or worse, if by some miracle you did give it arguments that worked but intended the static method to be called, then your code would be broken in a very bizarre and hard-to-debug way.
Extension methods were added very late in the game and the rules for looking them up make them deliberately prefer giving errors to magically working. This is a safety system to ensure that extension methods are not bound by accident.