Reputation: 20353
Can anyone explain why for these methods:
public IEnumerable<Role> GetRoles(Func<Role, bool> predicate = null)
public IEnumerable<Role> GetRoles(params User[] users)
If I call GetRoles(null)
it won't compile because the method call is ambiguous, and rightly so, but if I call GetRoles()
this is legal and selects the public IEnumerable<Role> GetRoles(Func<Role, bool> predicate = null)
method. Why is this not also ambiguous?
Upvotes: 0
Views: 623
Reputation: 78155
A call to GetRoles()
is not ambiguous because in the absence of parameters, GetRoles(params User[] users)
only applies in its expanded form*, and §12.6.4.3 of the C# language specification specifies that in a case of a tie certain tie-breaking rules apply, the second one being:
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.
Thus GetRoles(Func<Role, bool> predicate = null)
is ruled to be better than GetRoles(params User[] users)
.
In a call to GetRoles(null)
, however, the params User[] users
applies both in expanded and in non-expanded form, in which case the expanded form is discarded. This leaves you with:
GetRoles(Func<Role, bool> predicate = null)
GetRoles(User[] users)
and now there is no way to choose a better match for GetRoles(null)
. You have to give a type to that null
so that overload resolution can pick the best candidate based on that.
* The expanded form is constructed by replacing the parameter array in the function member declaration with zero or more value parameters of the element type of the parameter array such that the number of arguments in the argument list
A
matches the total number of parameters.
C# Language specification, §12.6.4.2
Upvotes: 3
Reputation: 56423
This is because both parameters are nullable and hence both methods could take a null
value as input and there's no way to distinguish them.
The compiler doesn't know if null
should be Func<Role, bool>
or User[] users
and doesn't have enough information to make any assumptions on the method to invoke.
You can provide more information to the compiler as follows:
Func<Role, bool> predicate = null;
GetRoles(predicate); // calls --> GetRoles(Func<Role, bool> predicate = null)
and for the other method:
User[] users = null;
GetRoles(users); // calls GetRoles(params User[] users)
Upvotes: -1