Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Why doesn't the C# ternary operator work with delegates?

Tags:

When branching to select a function, it might make sense to use the ternary operator to select a function, but this is impossible. Why?

public class Demo {     protected bool branch;     protected void demo1 () {}     protected void demo2 () {}     public Action DoesntWork() {         return branch ? demo1 : demo2;     } } 

The compiler produces the following error:

Cannot implicitly convert type `method group' to `System.Action' 
like image 269
Foxor Avatar asked Oct 14 '14 19:10

Foxor


People also ask

Why is there no string in C?

Both Java and Python have the concept of a "string", C does not have the concept of a "string". C has character arrays which can come in "read only" or manipulatable. A character array is a sequence of contiguous characters with a unique sentinel character at the end (normally a NULL terminator '\0' ).

Why is C not A or B?

Because C comes after B The reason why the language was named “C” by its creator was that it came after B language. Back then, Bell Labs already had a programming language called “B” at their disposal.

Why C has no exception handling?

As such, C programming does not provide direct support for error handling but being a system programming language, it provides you access at lower level in the form of return values. Most of the C or even Unix function calls return -1 or NULL in case of any error and set an error code errno.

Why array bounds checking is not available in C?

C # in Telugu Languages like Java and python have bounds checking so if you try to access an out of bounds element, they throw an error. C++ design principle was that it shouldn't be slower than the equivalent C code, and C doesn't do array bounds checking.


2 Answers

The problem is that demo1 is not a simple expression, it is a method. And methods can be overriden, so it is not actually one method, it is a method group. Consider the following example:

public class Demo {     protected bool branch;     protected void demo1 (int) {}     protected void demo1 () {}     protected void demo2 () {}     public Action DoesntWork() {         return branch ? demo1 : demo2; //Error         return demo1; //ok     } } 

Now, demo1 is overloaded, so which one of the two versions should be used? The answer is that the overloaded function is selected by using the context in which the function is used.

In the return demo1 it is obvious, it expects an Action.

But in the return branch? demo1 : demo2; the context is not so easy. The ternary operator first tries to match the type of demo1 with that of demo2, but that is another method group so there is no help there. The compiler does not look beyond and fails.

The solution is to make clear the type expected from the method group:

return branch? new Action(demo1) : demo2;  return branch? (Action)demo1 : demo2;  Action d1 = demo1; return branch? d1 : demo2; 
like image 91
rodrigo Avatar answered Sep 20 '22 13:09

rodrigo


You have to explicitly create the delegate of the appropriate type. Normally, you can just use demo1 to refer to a System.Action, but that is only because the compiler can infer the type based on the usage and creates the delegate for you. In this case, the compiler doesn't know that your method should be converted to System.Action when used within the ternary operator.

If you supply this yourself for even one of the arguments, it will work:

public Action DoesWork()  {     return branch ? demo1 : new Action(demo2); } 

Since this returns new Action explicitly for one argument, the compiler can infer that the other should be converted appropriate to a System.Action, and it will compile successfully.

like image 29
Reed Copsey Avatar answered Sep 22 '22 13:09

Reed Copsey