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)
Conditional Operators The logical AND and logical OR operators both take two operands. Each operand is a boolean expression (i.e., it evaluates to either true or false). The logical AND condition returns true if both operands are true, otherwise, it returns false.
A conditional operator in C#, is an operator that takes three operands (conditions to be checked), the value when the condition is true and value when the condition is false.
In certain computer programming languages, the Elvis operator, often written ?: , or or || , is a binary operator that returns its first operand if that operand evaluates to a true value, and otherwise evaluates and returns its second operand.
Introduced in C# 6.0, the Null Conditional Operator ?. will immediately return null if the expression on its left-hand side evaluates to null , instead of throwing a NullReferenceException . If its left-hand side evaluates to a non- null value, it is treated just like a normal .
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 if
works.
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:
object = someBool ? "" : New List<Integer>();
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:
object = someBool ? (object) "" : New List<Integer>();
If you have an expression like your CompareByKey
, it doesn't have any specific .Net type, but has a special type “method group”. That's because you could have several methods called CompareByKey
and it's unclear which one do you want (and it works exactly the same even if you have only one method). Also, it's unclear what delegate type do you want, e.g. Comparison<KeyValuePair<int, string>>
or Func<KeyValuePair<int, string>, int>
.
What can you do with method groups? You can use them to explicitly create a delegate (new Comparison<KeyValuePair<int, string>>(CompareByKey)
) and they are also implicitly convertible to delegates. This is why your if
version works.
So, what does that have to do with your problem? When you have a conditional operator, the compiler has to figure out the type of the whole expression and it can't use the type of the variable you assign it to (that's not how type inference works in C#). And since both of the expressions are method groups and method groups are treated as different types with no implicit conversions between each other, the type of the whole expression cannot be determined. Which is why you get the error.
You already found a fix: either don't use conditional operator or specify the type of one of the operands explicitly by using a cast (or delegate constructor).
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With