Given two implementations of Comparison methods:
// compares by Key...
private static int CompareByKey(KeyValuePair<int, string> x, KeyValuePair<int, string> y)
{
return x.Key.CompareTo(y.Key);
}
// compares by Value...
private static int CompareByValue(KeyValuePair<int, string> x, KeyValuePair<int, string> y)
{
return x.Value.CompareTo(y.Value);
}
Why wouldn’t the following conditional operator code block compile:
Comparison<KeyValuePair<int, string>> sortMethod;
sortMethod = isSortByActualValue ? CompareByKey : CompareByValue;
Compiler error: “Type of conditional expression cannot be determined because there is no implicit conversion between ‘method group’ and ‘method group'”
However, the equivalent code block using if-else does not have any issue:
Comparison<KeyValuePair<int, string>> sortMethod;
if (isSortByActualValue)
sortMethod = CompareByKey;
else
sortMethod = CompareByValue;
(all good in both assignments above)
So does the conditional operator, if I cast the Comparison delegate:
Comparison<KeyValuePair<int, string>> sortMethod;
sortMethod = isSortByActualValue ? (Comparison<KeyValuePair<int, string>>) CompareByKey : CompareByValue;
(all good in the assignment above, when cast even though casting was only on the true part)
Th error method actually says it all but it’s not quite intuitive. If you use a method name without invoking the method, you are handling a method group. “group”, because a method could be overloaded and the name can indicate any of the overloaded methods.
Now, method groups are convertible implicitly to a delegate with matching signature, this is why your assignment in
ifworks.So far, so good. However, the conditional operator
?:needs to deduce a common type to which its second and third arguments can be implicitly converted, and it does not consider all conversions for that (this would have diverse problems). It merely looks whether both arguments have the same type, or whether one is implicitly convertible into the other.This is not the case here: although both arguments are method groups, they are in fact different method groups with distinct types, and you cannot convert one method group into another. Even though both can readily be converted into a delegate, the compiler forbids this usage.
The same is true for other types, by the way:
also fails to compile, for the same reason. And again, we can make this compile by explicitly casting either of the arguments to a common base type: