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?
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:
Put all the possible methods in a big bucket -- extension methods, static methods, instance methods, etc.
If there are methods that would be an error to use, eliminate them from the bucket.
Of the remaining methods, choose the unique one that has the best match of argument expressions to parameter types.
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:
Put all the instance and static methods in a bucket. Virtual overrides are not counted as instance methods.
Eliminate the methods that are inapplicable because the arguments do not match the parameters.
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
mystring.Join(foo, bar);
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.
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:
The set of candidate methods for the method invocation is constructed. For each method F associated with the method group M:
If F is non-generic, F is a candidate when:
M has no type argument list, and
F is applicable with respect to A (§7.5.3.1).
According to the above, double.Floor(decimal) is a valid candidate.
If the resulting set of candidate methods is empty, then further processing along the following steps are abandoned, and instead an attempt is made to process the invocation as an extension method invocation (§7.6.5.2). If this fails, then no applicable methods exist, and a binding-time error occurs.
In your case the set of candidate methods is not empty, so extension methods are not considered.
The signature of decimal.Floor is
public static Decimal Floor(Decimal d);
I'm no specialist in type inference, but I guess since there is a implicit conversion from int to Decimal the compiler chooses this as the best fitting method.
If you change your signature to
public static decimal Floor(
this decimal value,
double precision)
and call it like
(10.1234m).Floor(2d)
it works. But of course a double as precision is somewhat strange.
EDIT: A quote from Eric Lippert on the alogrithm:
Any method of the receiving type is closer than any extension method.
Floor is a method of the "receiving type" (Decimal). On the why the C# developers implemented it like this I can make no statement.
Related
I recently noticed that C# compiler allows methods overloads like the following:
public static string foo(string a, bool x = false)
{
return "a";
}
public static string foo(string a)
{
return "b";
}
As far as I tested, it always returns "b" as long as the second param is not given, which makes sense. However, I think the compiler really should not allow this type of overloading. May I ask the reason why this feature is designed like this rather than giving an error by compiler?
While questions like this are fundamentally impossible to answer, since it is impossible to guess the language designers intentions, I might make a guess.
Optional arguments are handled by transforming the code to inject the argument to the call site. So
public static void Test(int a = 42){...}
...
Test();
would be transformed to to
public static void Test(int a){...}
...
Test(42);
by the compiler. From this point on the regular overload resolution can run without conflicts. Why was it designed this way? I have no idea, but common reasons for non intuitive features is backward compatibility or language compatibility.
For this reason it is important to be very careful using optional arguments in public APIs. Since the user of the library will use the default value from the version of the API it was compiled against. Not the version it is running against.
I can't speak to why this is part of the design so much as simply explain why you see which overload is favored in your testing.
If you look at the reference documentation, you'll note the following three bullets to describe overload resolution:
A method, indexer, or constructor is a candidate for execution if each of its parameters either is optional or corresponds, by name or by position, to a single argument in the calling statement, and that argument can be converted to the type of the parameter.
If more than one candidate is found, overload resolution rules for preferred conversions are applied to the arguments that are explicitly specified. Omitted arguments for optional parameters are ignored.
If two candidates are judged to be equally good, preference goes to a candidate that doesn't have optional parameters for which arguments were omitted in the call. Overload resolution generally prefers candidates that have fewer parameters.
I would assert that in your test, bullet #3 is most applicable to your observations - because you omit the second argument and either method is equally good, resolution favors your second method and you see "b" returned.
My class currently has two constructors, which are overloads:
public CustomRangeValidationAttribute(string value) {}
and
public CustomRangeValidationAttribute(object value) {}
this appears to be working correctly: When I call the method using a string the first constructor is called, when I use different values, for example an integer or boolean, the second constructor is called.
I assume there is a rule to force specific type matches into the more specific overload, preventing
var c = new CustomRangeValidationAttrubute("test");
from calling the object-overload.
Is this "safe code", or should (or can) the code be improved? I have a nagging feeling this is not the best practice.
You have two overloads which only vary in the reference types and there's a hierarchical relationship between the reference types, such that one may be cast to the other.
In such a circumstance, you really ought to make sure that the code behaves the same logically when the broader overload is selected but the reference turns out to be of the more derived type1,2. That is where to focus your attention. Of course, if you can stick by this rule, often it'll turn out that the more derived overload isn't required and can just be special-cased within the broader method.
1Especially because, as vc74 points out in a comment, overload resolution (generally, ignoring dynamic) is done at compile time based on compile-time types3.
2And this fits the same broad principal for overloads. Don't have overloads where which one is selected leads to logically different results. If you're exhibiting different behaviours, don't give them the same name (for constructors, that may mean splitting into two separate classes, possibly with a shared base class, if that's what you intend to do)
3I appreciate that this is for an attribute and so you're expecting only compile-time to be relevant, but I'd still hew to the general principal here, where possible.
Once there is overload with signature of more derived type the compiler will always choose most concrete type you provide.
That being said, unless someone does new CustomRangeValidationAttrubute((object)"test") if you pass string to CustomRangeValidationAttrubute always constructor with string in it's parameter will be chosen.
About if this is bad practice, I can't tell for sure if I don't see your specific use case, just keep in mind every value type you pass to new CustomRangeValidationAttrubute(object) will be boxed and this is bad as it puts pressure to the GC and whats more you will loose type safety.
The way I resolved this code was by moving the overloads to a new abstract class with separate methods instead of the the original constructors:
public CustomRangeValidationStringAttribute(string value) {}
public CustomRangeValidationGenericAttribute(object value) {}
In the two classes inheriting from this new base class each use their own method, creating two different attributes to choose from, [CustomRangeValidationString] and [CustomRangeValidationGeneric].
You could use a generic class.
See the documentation
class YourClass<T>
{
public YourClass(T value){}
}
I have recently found an interesting behavior of C# compiler. Imagine an interface like this:
public interface ILogger
{
void Info(string operation, string details = null);
void Info(string operation, object details = null);
}
Now if we do
logger.Info("Create")
The compiler will complain that he does not know which overload to chose (Ambiguous invocation...). Seems logical, but when you try to do this:
logger.Info("Create", null)
It will suddenly have no troubles figuring out that null is a string. Moreover it seems that the behavior of finding the right overload has changed with time and I had found a bug in an old code that worked before and stopped working because compiler decided to use another overload.
So I am really wondering why does C# not generate the same error in the second case as it does in the first. Seems very logical to do this, but instead it tries and resolves it to random overload.
P.S. I don't think that it's good to provide such ambiguous interfaces and do not recommend that, but legacy is legacy and has to be maintained :)
There was a breaking change introduced in C# 6 that made the overload resolution better. Here it is with the list of features:
Improved overload resolution
There are a number of small improvements to overload resolution, which will likely result in more things just working the way you’d expect them to. The improvements all relate to “betterness” – the way the compiler decides which of two overloads is better for a given argument.
One place where you might notice this (or rather stop noticing a problem!) is when choosing between overloads taking nullable value types. Another is when passing method groups (as opposed to lambdas) to overloads expecting delegates. The details aren’t worth expanding on here – just wanted to let you know!
but instead it tries and resolves it to random overload.
No, C# doesn't pick overloads randomly, that case is the ambiguous call error. C# picks the better method. Refer to section 7.5.3.2 Better function member in the C# specs:
7.5.3.2 Better function member
Otherwise, if MP has more specific parameter types than MQ, then MP is better than MQ. Let {R1, R2, …, RN} and {S1, S2, …, SN} represent the uninstantiated and unexpanded parameter types of MP and MQ. MP’s parameter types are more specific than MQ’s if, for each parameter, RX is not less specific than SX, and, for at least one parameter, RX is more specific than SX:
Given that string is more specific than object and there is an implicit cast between null and string, then the mystery is solved.
I have found this topic, but it's VB...and they get an error:
vb issue
Here are my method signatures. Notice one has a different return type.
public static bool PopulateRunWithSimpleValueByFieldIdSync(string fieldValue, string fieldId, IViewModel myself, int index)
VS
public static void PopulateRunWithSimpleValueByFieldIdSync(string fieldValue, string fieldId, IViewModel myself, int index = 0, PopulateDoneCallback populateDone = null)
The actual call I was making:
PopulateRunWithSimpleValueByFieldIdSync(date, dtx.DateField, saver, index);
The compiler decided to pick the first method, and not give me an error. Once the first method was removed (it was unused code), it started calling the second method.
Is there an option somewhere to treat this as an error?
You're going to need to use some form of 3rd party code analysis if you want this to be flagged at compile time, since the C# language specs define the current behavior as what should happen.
According to the C# language guide (emphasis mine),
Use of named and optional arguments affects overload resolution in the following ways:
...
If two candidates are judged to be equally good, preference goes to a candidate that does not have optional parameters for which arguments were omitted in the call. This is a consequence of a general preference in overload resolution for candidates that have fewer parameters.
You can use a third party analysis tool to flag this as an error or to use Visual Studio's built in static code analysis too with a custom rule that you implement.
This is per design, according to the specs
Use of named and optional arguments affects overload resolution in the
following ways:
A method, indexer, or constructor is a candidate for execution if each of its parameters either is optional or corresponds, by name or
by position, to a single argument in the calling statement, and that
argument can be converted to the type of the parameter.
If more than one candidate is found, overload resolution rules for preferred conversions are applied to the arguments that are explicitly
specified. Omitted arguments for optional parameters are ignored.
If two candidates are judged to be equally good, preference goes to a candidate that does not have optional parameters for which arguments
were omitted in the call. This is a consequence of a general
preference in overload resolution for candidates that have fewer
parameters.
So, no - you can't.
Is there a cost associated with overloading methods in .Net?
So if I have 3 methods like:
Calculate (int)
Calculate (float)
Calculate (double)
and these methods are called at runtime "dynamically" based on what's passed to the Calculate method, what would be the cost of this overload resolution?
Alternatively I could have a single Calculate and make the difference in the method body, but I thought that would require the method to evaluate the type every time it's called.
Are there better ways/designs to solves this with maybe no overhead? Or better yet, what's the best practice to handle cases like these? I want to have the same class/method name, but different behaviour.
EDIT: Thanks all. Jusdt one thing if it's any different. I was wondering say you have a DLL for these methods and a program written in C# that allows the user to add these methods as UI items (without specifying the type). So the user adds UI item Calculate (5), and then Calculate (12.5), etc, and the C# app executes this, would there still be no overhead?
As far as the runtime is concerned these are different methods. Is the same as writing:
CalculateInt(int)
CalculateFloat(float)
Regarding the performance issues, except very special cases, you can safely ignore the method call overhead.
This question is about method overloading, not polymorphism. As far as I know, there isn't a penalty for method overloading, since the compiler will figure out which method to call at compile time based on the type of the argument being pass to it.
Polymorphism only comes into play where you are using a derived type as a substitute for a base class.
First, unless your profiler is telling you there's a performance problem, you shouldn't sacrifice good design for assumed performance gains.
To answer your question, the resolution of method calls isn't dynamic. It's determined at compile time, so there's no cost in that respect. The only cost would be in the potential implicit casting of a type to fit the parameter type.
The method overload (i.e. the method table slot) is not resolved dynamically at runtime, it is resolved statically at compile time, so there is zero cost in having overloaded methods.
I assume you're thinking of virtual methods where the actual implementation may be overridden by a derived type and the actual method picked based on the concrete type. But that has nothing to do with overloading as virtual methods occupy the same method table slot.
There is no "cost" at run time because the compiler determines which method to call at compile time. The IL that is generated specifically calls the method that takes the appropriate parameters.
Take this for example"
public class Calculator
{
public void Calculate(int value)
{
//Do Something
}
public void Calculate(decimal value)
{
//Do Something
}
public void Calculate(double value)
{
//Do Something
}
}
static void Main(string[] args)
{
int i = 0;
Calculator calculator = new Calculator();
calculator.Calculate(i);
}
The following call is made in IL to calculate the variable "i":
L_000b: callvirt instance void ConsoleApplication1.Calculator::Calculate(int32)
Notice that it specifies the method is of type int32 which is the same type as the variable passed in from the Main method.
So if there is a cost at all it's only at compile time. No worries.
As JaredPar noted below:
There is a misconception in your question. Overloaded methods in C# are
not called dynamically at runtime. All
method calls are bound statically at
compile time. Hence there is no
"searching" for a method at runtime,
it's predetermined at compile time
which overload will be called.
3 different methods are produced in IL based on the type. The only cost will be if you are casting from one type to another, but that cost won't be significant unless you have a large amount to do. So you could stick to Calculate(double) and cast from there.
There is a misconception in your question. Overloaded methods in C# are not called dynamically at runtime. All method calls are bound statically at compile time. Hence there is no "searching" for a method at runtime, it's predetermined at compile time which overload will be called.
Note: This changes a bit with C# 4.0 and dynamic. With a dynamic object it is possible that an overload will be chosen at runtime based on the type of the object. This is not the case with C# 3.0 and below though.