public enum EnumTest
{
EnumEntry
}
public class TestClass
{
public string FunctionMember(string s, EnumTest t = EnumTest.EnumEntry)
{
return "Normal";
}
public string FunctionMember<T>(T t)
{
return "Generic";
}
}
class Program
{
static void Main(string[] args)
{
TestClass t = new TestClass();
Console.WriteLine(t.FunctionMember("a"));
}
}
This prints "Generic". Removing , EnumTest t = EnumTest.EnumEntry makes it print "Normal".
And yet the standard appears to be pretty clear, from 14.4.2.2 Better function member the first discriminator to be applied is:
If one of MP and MQ is non-generic, but the other is generic, then the non-generic is better.
Am I missing something or compiler bug?
You are missing something. And that is the following:
You call the method with one parameter. There is only one method that has one parameter, the generic one. So that's the one that's chosen.
Only if it didn't find a matching method it would look at other methods with optional parameters.
References:
C# 4.0 Specification, last paragraph in 21.4:
As a tie breaker rule, a function member for which all arguments where explicitly given is better than one for which default values were supplied in lieu of explicit arguments.
MSDN, heading "Overload resolution", last bullet point:
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.
The C# Language Specification, Chapter "7.5.3.2 Better function member":
Parameter lists for each of the candidate function members are constructed in the following way:
The expanded form is used if the function member was applicable only in the expanded form.
Optional parameters with no corresponding arguments are removed from the parameter list
It continues like this:
Given an argument list A with a set of argument expressions { E1, E2, ..., EN } and two applicable function members MP and MQ with parameter types { P1, P2, ..., PN } and { Q1, Q2, ..., QN } [...]
At this point the method with the optional parameter is already out of the game. N is 1, but that method has two parameters.
The docs say:
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.
In other words, the method without any optional arguments will be preferred.
With default values for method parameters the overload resolution got extended.
Conceptually the method overload resolution from pre v4 will be run. If that finds a match that match will be used. (Conceptually because this is not a description of how it works but how you can think of it)
In your case it finds exactly one match being your generic method
If it does not find a match it will look for methods that has a partial match and where the match can be completed with default values. In your case your none generice method would be found in this run however the resolution never comes this far due to already having found a match.
When removing the second paramter you end up in a situation where there's a generic and a non generic match. And the rule you qoute kicks in picking the non-generic.
All in all a good rule of thumb is that the most specific available method will be chosen.
A non-generic method that matches is more specific than a generic because the type can't vary.
A method with default parameters is less specific than one where the argument count matches the parameter count (the numbers are an exact match)
if two methods are available but one takes an argument of IFoo and the other takes a Foo (implemeting IFoo) then the latter will be chosen when passing a Foo object as argument because it's an exact match Ie. more specific
Related
The following call to the overloaded Enumerable.Select method:
var itemOnlyOneTuples = "test".Select<char, Tuple<char>>(Tuple.Create);
fails with an ambiguity error (namespaces removed for clarity):
The call is ambiguous between the following methods or properties:
'Enumerable.Select<char,Tuple<char>>
(IEnumerable<char>,Func<char,Tuple<char>>)'
and
'Enumerable.Select<char,Tuple<char>>
(IEnumerable<char>, Func<char,int,Tuple<char>>)'
I can certainly understand why not specifying the type-arguments explicitly would result in an ambiguity (both the overloads would apply), but I don't see one after doing so.
It appears clear enough to me that the intention is to call the first overload, with the method-group argument resolving to Tuple.Create<char>(char). The second overload should not apply because none of the Tuple.Create overloads can be converted to the expected Func<char,int,Tuple<char>> type. I'm guessing the compiler is confused by Tuple.Create<char, int>(char, int), but its return-type is wrong: it returns a two-tuple, and is hence not convertible to the relevant Func type.
By the way, any of the following makes the compiler happy:
Specifying a type-argument for the method-group argument: Tuple.Create<char> (Perhaps this is actually a type-inference issue?).
Making the argument a lambda-expression instead of a method-group: x => Tuple.Create(x). (Plays well with type-inference on the Select call).
Unsurprisingly, trying to call the other overload of Select in this manner also fails:
var itemIndexTwoTuples = "test".Select<char, Tuple<char, int>>(Tuple.Create);
What's the exact problem here?
First off, I note that this is a duplicate of:
Why is Func<T> ambiguous with Func<IEnumerable<T>>?
What's the exact problem here?
Thomas's guess is essentially correct. Here are the exact details.
Let's go through it a step at a time. We have an invocation:
"test".Select<char, Tuple<char>>(Tuple.Create);
Overload resolution must determine the meaning of the call to Select. There is no method "Select" on string or any base class of string, so this must be an extension method.
There are a number of possible extension methods for the candidate set because string is convertible to IEnumerable<char> and presumably there is a using System.Linq; in there somewhere. There are many extension methods that match the pattern "Select, generic arity two, takes an IEnumerable<char> as the first argument when constructed with the given method type arguments".
In particular, two of the candidates are:
Enumerable.Select<char,Tuple<char>>(IEnumerable<char>,Func<char,Tuple<char>>)
Enumerable.Select<char,Tuple<char>>(IEnumerable<char>,Func<char,int,Tuple<char>>)
Now, the first question we face is are the candidates applicable? That is, is there an implicit conversion from each supplied argument to the corresponding formal parameter type?
An excellent question. Clearly the first argument will be the "receiver", a string, and it will be implicitly convertible to IEnumerable<char>. The question now is whether the second argument, the method group "Tuple.Create", is implicitly convertible to formal parameter types Func<char,Tuple<char>>, and Func<char,int, Tuple<char>>.
When is a method group convertible to a given delegate type? A method group is convertible to a delegate type when overload resolution would have succeeded given arguments of the same types as the delegate's formal parameter types.
That is, M is convertible to Func<A, R> if overload resolution on a call of the form M(someA) would have succeeded, given an expression 'someA' of type 'A'.
Would overload resolution have succeeded on a call to Tuple.Create(someChar)? Yes; overload resolution would have chosen Tuple.Create<char>(char).
Would overload resolution have succeeded on a call to Tuple.Create(someChar, someInt)? Yes, overload resolution would have chosen Tuple.Create<char,int>(char, int).
Since in both cases overload resolution would have succeeded, the method group is convertible to both delegate types. The fact that the return type of one of the methods would not have matched the return type of the delegate is irrelevant; overload resolution does not succeed or fail based on return type analysis.
One might reasonably say that convertibility from method groups to delegate types ought to succeed or fail based on return type analysis, but that's not how the language is specified; the language is specified to use overload resolution as the test for method group conversion, and I think that's a reasonable choice.
Therefore we have two applicable candidates. Is there any way that we can decide which is better than the other? The spec states that the conversion to the more specific type is better; if you have
void M(string s) {}
void M(object o) {}
...
M(null);
then overload resolution chooses the string version because string is more specific than object. Is one of those delegate types more specific than the other? No. Neither is more specific than the other. (This is a simplification of the better-conversion rules; there are actually lots of tiebreakers, but none of them apply here.)
Therefore there is no basis to prefer one over the other.
Again, one could reasonably say that sure, there is a basis, namely, that one of those conversions would produce a delegate return type mismatch error and one of them would not. Again, though, the language is specified to reason about betterness by considering the relationships between the formal parameter types, and not about whether the conversion you've chosen will eventually result in an error.
Since there is no basis upon which to prefer one over the other, this is an ambiguity error.
It is easy to construct similar ambiguity errors. For example:
void M(Func<int, int> f){}
void M(Expression<Func<int, int>> ex) {}
...
M(x=>Q(++x));
That's ambiguous. Even though it is illegal to have a ++ inside an expression tree, the convertibility logic does not consider whether the body of a lambda has something inside it that would be illegal in an expression tree. The conversion logic just makes sure that the types check out, and they do. Given that, there's no reason to prefer one of the M's over the other, so this is an ambiguity.
You note that
"test".Select<char, Tuple<char>>(Tuple.Create<char>);
succeeds. You now know why. Overload resolution must determine if
Tuple.Create<char>(someChar)
or
Tuple.Create<char>(someChar, someInt)
would succeed. Since the first one does and the second one does not, the second candidate is inapplicable and eliminated, and is therefore not around to become ambiguous.
You also note that
"test".Select<char, Tuple<char>>(x=>Tuple.Create(x));
is unambiguous. Lambda conversions do take into account the compatibility of the returned expression's type with the target delegate's return type. It is unfortunate that method groups and lambda expressions use two subtly different algorithms for determining convertibility, but we're stuck with it now. Remember, method group conversions have been in the language a lot longer than lambda conversions; had they been added at the same time, I imagine that their rules would have been made consistent.
I'm guessing the compiler is confused by Tuple.Create<char, int>(char, int), but its return-type is wrong: it returns a two-tuple.
The return type isn't part of the method signature, so it isn't considered during overload resolution; it's only verified after an overload has been picked. So as far as the compiler knows, Tuple.Create<char, int>(char, int) is a valid candidate, and it is neither better nor worse than Tuple.Create<char>(char), so the compiler can't decide.
I was surprised today by the way the method resolution works.
Here's the code as an exemple :
class Program
{
static class Mapper<TSource, TTarget>
{
public static void Map<TMember>(Expression<Func<TSource, TMember>> source, Expression<Func<TTarget, TMember>> target)
{
Console.WriteLine("A");
}
public static void Map<TMember, TSourceCollection>(Expression<Func<TSource, TSourceCollection>> source, Expression<Func<TTarget, TMember[]>> target)
where TSourceCollection : IEnumerable<TMember>
{
Console.WriteLine("B");
}
}
class A
{
public byte[] prop { get; set; }
}
class B
{
public byte[] prop { get; set; }
}
static void Main(string[] args)
{
Mapper<A, B>.Map(x => x.prop, x => x.prop);
}
}
As you see the method Map has two overloads, one when the type of the properties are the same, and one when the source property is an enumerable and the right property is an array.
Then when i call the method with an array on both sides it calls the second overload, but as the types are exactly the same i expected the first overload to be called.
I thought the first overload would have a better scoring because it depends on fewer generic arguments than the second, and it fits better with the types of the arguments i pass to the method.
Can someone explain why the compiler chooses to call the second overload instead of the first one please ?
Thanks.
Overload resolution is complicated and you can read the spec to understand why. One thing I am pretty sure of though is that it doesn't consider the need to specify less generic parameters when considering which overload is better (though it will take non-generic over generic but when both are generic it considers them equal).
When looking at the overloads it can choose from they are all equal apart from whether the second parameter is TMember or TMember[].
The spec talks a lot about choosing the most specific member and I can't work out which part is actually applicable here (there are many places where it talks about preferring X over Y when X is more specific). I would have thought it was either Section 7.6.5.1 (of the c#5 spec) which is where it constructs a candidate list or section 7.5.3 where it deals with overload resolution. However the former doesn't seem to exclude either method overload and the latter to my reading only deals with the parameters after the generic ones have been substituted in at which point they are identical. It may be that there is somewhere else in the spec that deals with this (eg when it infers the type arguments).
In woolly terms though I believe that the compiler is considering that TMember[] is more specific than TMember. This can be broadly seen to be true because TMember will accept more things than TMember[] will so TMember[] is more specific.
The matching of first method TMember and second method TSourceCollection is of equal value for any type that satisfies the where TSourceCollection : IEnumerable<TMember> condition.
The type TMember[] is a more detailed type match for byte[] compared to TMember. So this should be the point where the second method scores better than the first. Consequently, this 'better' match outrules the fact, that method two has more generic parameters.
The following call to the overloaded Enumerable.Select method:
var itemOnlyOneTuples = "test".Select<char, Tuple<char>>(Tuple.Create);
fails with an ambiguity error (namespaces removed for clarity):
The call is ambiguous between the following methods or properties:
'Enumerable.Select<char,Tuple<char>>
(IEnumerable<char>,Func<char,Tuple<char>>)'
and
'Enumerable.Select<char,Tuple<char>>
(IEnumerable<char>, Func<char,int,Tuple<char>>)'
I can certainly understand why not specifying the type-arguments explicitly would result in an ambiguity (both the overloads would apply), but I don't see one after doing so.
It appears clear enough to me that the intention is to call the first overload, with the method-group argument resolving to Tuple.Create<char>(char). The second overload should not apply because none of the Tuple.Create overloads can be converted to the expected Func<char,int,Tuple<char>> type. I'm guessing the compiler is confused by Tuple.Create<char, int>(char, int), but its return-type is wrong: it returns a two-tuple, and is hence not convertible to the relevant Func type.
By the way, any of the following makes the compiler happy:
Specifying a type-argument for the method-group argument: Tuple.Create<char> (Perhaps this is actually a type-inference issue?).
Making the argument a lambda-expression instead of a method-group: x => Tuple.Create(x). (Plays well with type-inference on the Select call).
Unsurprisingly, trying to call the other overload of Select in this manner also fails:
var itemIndexTwoTuples = "test".Select<char, Tuple<char, int>>(Tuple.Create);
What's the exact problem here?
First off, I note that this is a duplicate of:
Why is Func<T> ambiguous with Func<IEnumerable<T>>?
What's the exact problem here?
Thomas's guess is essentially correct. Here are the exact details.
Let's go through it a step at a time. We have an invocation:
"test".Select<char, Tuple<char>>(Tuple.Create);
Overload resolution must determine the meaning of the call to Select. There is no method "Select" on string or any base class of string, so this must be an extension method.
There are a number of possible extension methods for the candidate set because string is convertible to IEnumerable<char> and presumably there is a using System.Linq; in there somewhere. There are many extension methods that match the pattern "Select, generic arity two, takes an IEnumerable<char> as the first argument when constructed with the given method type arguments".
In particular, two of the candidates are:
Enumerable.Select<char,Tuple<char>>(IEnumerable<char>,Func<char,Tuple<char>>)
Enumerable.Select<char,Tuple<char>>(IEnumerable<char>,Func<char,int,Tuple<char>>)
Now, the first question we face is are the candidates applicable? That is, is there an implicit conversion from each supplied argument to the corresponding formal parameter type?
An excellent question. Clearly the first argument will be the "receiver", a string, and it will be implicitly convertible to IEnumerable<char>. The question now is whether the second argument, the method group "Tuple.Create", is implicitly convertible to formal parameter types Func<char,Tuple<char>>, and Func<char,int, Tuple<char>>.
When is a method group convertible to a given delegate type? A method group is convertible to a delegate type when overload resolution would have succeeded given arguments of the same types as the delegate's formal parameter types.
That is, M is convertible to Func<A, R> if overload resolution on a call of the form M(someA) would have succeeded, given an expression 'someA' of type 'A'.
Would overload resolution have succeeded on a call to Tuple.Create(someChar)? Yes; overload resolution would have chosen Tuple.Create<char>(char).
Would overload resolution have succeeded on a call to Tuple.Create(someChar, someInt)? Yes, overload resolution would have chosen Tuple.Create<char,int>(char, int).
Since in both cases overload resolution would have succeeded, the method group is convertible to both delegate types. The fact that the return type of one of the methods would not have matched the return type of the delegate is irrelevant; overload resolution does not succeed or fail based on return type analysis.
One might reasonably say that convertibility from method groups to delegate types ought to succeed or fail based on return type analysis, but that's not how the language is specified; the language is specified to use overload resolution as the test for method group conversion, and I think that's a reasonable choice.
Therefore we have two applicable candidates. Is there any way that we can decide which is better than the other? The spec states that the conversion to the more specific type is better; if you have
void M(string s) {}
void M(object o) {}
...
M(null);
then overload resolution chooses the string version because string is more specific than object. Is one of those delegate types more specific than the other? No. Neither is more specific than the other. (This is a simplification of the better-conversion rules; there are actually lots of tiebreakers, but none of them apply here.)
Therefore there is no basis to prefer one over the other.
Again, one could reasonably say that sure, there is a basis, namely, that one of those conversions would produce a delegate return type mismatch error and one of them would not. Again, though, the language is specified to reason about betterness by considering the relationships between the formal parameter types, and not about whether the conversion you've chosen will eventually result in an error.
Since there is no basis upon which to prefer one over the other, this is an ambiguity error.
It is easy to construct similar ambiguity errors. For example:
void M(Func<int, int> f){}
void M(Expression<Func<int, int>> ex) {}
...
M(x=>Q(++x));
That's ambiguous. Even though it is illegal to have a ++ inside an expression tree, the convertibility logic does not consider whether the body of a lambda has something inside it that would be illegal in an expression tree. The conversion logic just makes sure that the types check out, and they do. Given that, there's no reason to prefer one of the M's over the other, so this is an ambiguity.
You note that
"test".Select<char, Tuple<char>>(Tuple.Create<char>);
succeeds. You now know why. Overload resolution must determine if
Tuple.Create<char>(someChar)
or
Tuple.Create<char>(someChar, someInt)
would succeed. Since the first one does and the second one does not, the second candidate is inapplicable and eliminated, and is therefore not around to become ambiguous.
You also note that
"test".Select<char, Tuple<char>>(x=>Tuple.Create(x));
is unambiguous. Lambda conversions do take into account the compatibility of the returned expression's type with the target delegate's return type. It is unfortunate that method groups and lambda expressions use two subtly different algorithms for determining convertibility, but we're stuck with it now. Remember, method group conversions have been in the language a lot longer than lambda conversions; had they been added at the same time, I imagine that their rules would have been made consistent.
I'm guessing the compiler is confused by Tuple.Create<char, int>(char, int), but its return-type is wrong: it returns a two-tuple.
The return type isn't part of the method signature, so it isn't considered during overload resolution; it's only verified after an overload has been picked. So as far as the compiler knows, Tuple.Create<char, int>(char, int) is a valid candidate, and it is neither better nor worse than Tuple.Create<char>(char), so the compiler can't decide.
I have a class Executive with the following code for that class:
public class Executive
{
public Executive(int Id = 0)
{
// Constructor 1
this.BaseSalary = 3000;
Console.Write("DONE");
}
public Executive()
{
// Constructor 2
Console.Write("done");
}
}
And in main I do the following:
Executive exec = new Executive()
It always calls Constructor 2.
Why doesn't it call Constructor 1 (since Id has a default value)?
That's how determining best method to call is done. Optional parameters without specified values are removed from arguments list when overload resolution is performed:
7.5.3.2 Better function member
For the purposes of determining the better function member, a stripped-down argument list A is constructed containing just the argument expressions themselves in the order they appear in the original argument list. Parameter lists for each of the candidate function members are constructed in the following way:
• The expanded form is used if the function member was applicable only in the expanded form.
• Optional parameters with no corresponding arguments are removed from the parameter list
• The parameters are reordered so that they occur at the same position as the corresponding argument in the argument list.
Also later in the same paragraph:
In case the parameter type sequences {P1, P2, …, PN} and {Q1, Q2, …, QN} are equivalent (i.e. each Pi has an identity conversion to the corresponding Qi), the following tie-breaking rules are applied, in order, to determine the better function member.
• If MP is a non-generic method and MQ is a generic method, then MP is better than MQ.
• Otherwise, if MP is applicable in its normal form and MQ has a params array and is applicable only in its expanded form, then MP is better than MQ.
• Otherwise, if MP has more declared parameters than MQ, then MP is better than MQ. This can occur if both methods have params arrays and are applicable only in their expanded forms.
• Otherwise if all parameters of MP have a corresponding argument whereas default arguments need to be substituted for at least one optional parameter in MQ then MP is better than MQ.
Which means that if you have two methods that both have applicable parameters but one requires to use optional parameter value and the other one doesn't, the one without optional value is better.
As MarcinJuraszek points out, this is just how it's determined which constructor should be called. When you call the parameterless constructor, that one is determined to be the best fit.
A solution to your problem would be to just explicitly call one constructor from the other:
public class Executive
{
public Executive(int ID)
{
//constructor 1
this.BaseSalary = 3000;
Console.Write("DONE");
}
public Executive():this(0)
{
//constructor 2
Console.Write("done");
}
}
This question already has answers here:
Closed 10 years ago.
Possible Duplicate:
Generic methods and method overloading
Ok, I hit this one by accident... Giving this situation:
class Program {
static void Main( string[ ] args ) {
var obj = new gen<int>( );
Console.Write( obj[ 1 ] );
Console.ReadKey( );
}
}
class gen<T> {
public int this[ T i ] { get { return 2; } }
public int this[ int i ] { get { return 1; } }
}
It will always print 1. I would have expected for the compiler to complain, or the runtime to crash and burn and melt the CPU, but no, it is happy to print '1'
Of course I can make a choice to return either if I use any other type for the generic parameter. For giggles, I try using UInt as the generic type parmater, and I can differentiate between the calls, so the questions are:
Why C# does not freak out? Shouldn't Anders Hejlsberg feel a disturbance in the force?
How can I restrict a generic parameter from certain types? As in this T can be anything but ints (but long are OK)
I believe this is specified in section 7.5.3.2 of the C# 4 spec (Better Function Member).
Otherwise, if MP has more specific parameter types than MQ, then MP is better than MQ [...]
A type parameter is less specific than a nontype parameter
[...]
So here, the member with the T parameter is less specific than the member with the int parameter.
Try to design your way out of this one simply by not overloading like this. It's hard for indexers of course, but you could always provide methods instead (or possibly as well, as a fall-back).
EDIT: Note that if you have overloaded methods where both are type parameters, the compiler will complain:
public class Foo<T1, T2>
{
public void Bar(T1 t1) {}
public void Bar(T2 t2) {}
}
...
Foo<int, int> foo = new Foo<int, int>();
foo.Bar(10); // Error
Here neither method is more specific.
How can I restrict a generic parameter from certain types? As in this T can be anything but ints (but long are OK)
This is really an entirely separate question, but basically you can't. You can constrain type parameters in various ways, but not by explicitly including and excluding types. See the MSDN page on constraints for more information.
As Eric Lippert says:
The C# specification says that when you have a choice between calling ReallyDoIt(string) and ReallyDoIt(string) – that is,
when the choice is between two methods that have identical signatures,
but one gets that signature via generic substitution – then we pick
the “natural” signature over the “substituted” signature.
Also this process described in C# spec 7.5.3.2 (Better function member):
In case the parameter type sequences {P1, P2, …, PN} and {Q1, Q2, …, QN} are equivalent (i.e. each Pi has an identity conversion to the corresponding Qi), the following tie-breaking rules are applied, in order, to determine the better function member.
If MP is a non-generic method and MQ is a generic method, then MP is better than MQ (as John pointed, this is true when you have generic method, not generic type)
...
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:
A type parameter is less specific than a non-type parameter (this is your case - thus methods are not generic, and inferred parameter type equals to non-generic parameter type)
The C# compiler always chooses the more-specific versus the more-generic method if the call could fit in both =). That's why it doesn't freak out, he just follows his rules.
C# compiler doesn't freak out because both method are valid, and both can be called.
Here's an example that return "2":
Gen<Form> gen = new Gen<Form>();
textBox1.Text = gen[this].ToString();
Where "this" is a form. Of course, using an index accessor as an object instead of a number... Well, whatever, it works.
But like everybody else said, the compiler will prefer the explicit over the implicit.