This is following the rules for "Better function member" in the ECMA C# 5 standard, section 12.6.4.3:
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.
So at that point, we're comparing these two methods, effectively:
Task SetAsync(string key, string value, TimeSpan? expiration);
Task SetAsync<T>(string applicationName, string key, T value);
(In the generic method version, the expiration
parameter does not have a corresponding argument, so it's removed from the parameter list.)
The argument list is "Key", "Value", TimeSpan.FromMinutes(1)
, and T
is inferred to be TimeSpan
.
Next:
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 }, MP is defined to be a better function member than MQ if
- for each argument, the implicit conversion from EX to QX is not better than the implicit conversion from EX to PX, and
- for at least one argument, the conversion from EX to PX is better than the conversion from EX to QX.
For the first two parameters, there's no difference - because they're string
everywhere.
For the third parameter, the conversion for the non-generic method is from TimeSpan
to TimeSpan?
, and for the generic method it's from TimeSpan
to TimeSpan
(because T
is TimeSpan
).
The identity conversion of TimeSpan
to TimeSpan
is "better" (as per the rules of 12.6.4.4) than the implicit conversion of TimeSpan
to TimeSpan?
, so for that parameter, the generic method is "better"... and there's no parameter for which the non-generic method is "better", therefore overall the generic method is better.
If neither method had been found to be "better" in this stage (e.g. due to a parameter type of TimeSpan
instead of TimeSpan?
for the optional parameter) then the non-generic method would have been determined to be "better" by the tie-break rules following this stage. But by that point, the generic method has already been selected.