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