0

Why does line 16 does not build, but the rest does.

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace ConsoleApplication7
{
    class Program
    {
        public static Boolean functionPicker = true;

        static void Main(string[] args)
        {
            Action func = SomeFunction;
            Action funcOther = SomeOtherFunction;
            Action chosenFunc = ((functionPicker == true) ? SomeFunction : SomeOtherFunction); //This is line 16
            if (functionPicker)
            {
                chosenFunc = SomeFunction;
            }
            else
            {
                chosenFunc = SomeOtherFunction;
            }

        }

        public static void SomeFunction()
        {

        }

        public static void SomeOtherFunction()
        {

        }
    }
}
Mike de Klerk
  • 11,906
  • 8
  • 54
  • 76
  • What error does line 16 produce? – Bernd Linde Nov 13 '14 at 15:00
  • 1
    [You can't use the ternary (?:) operator there](http://stackoverflow.com/questions/564935/c-no-implicit-conversion-between-lambda-expression-and-lambda-expression). Turn it into a normal if/else. – Matthew Watson Nov 13 '14 at 15:02
  • @MatthewWatson In the question you're quoting, Jon shows exactly how this can be done (hint: a single cast). – decPL Nov 13 '14 at 15:27
  • @decPL I much prefer avoiding the cast personally. I think people overuse `?:` and wind up with less readable code. – Matthew Watson Nov 13 '14 at 15:54
  • @MatthewWatson I fully agree that it's overused, but I beg to differ in this particular scenario. Still - the notion that 'you can't use ?: here' is clearly wrong. – decPL Nov 13 '14 at 16:00
  • 1
    @decPL Ah well, I'm never going to agree that using a cast is better than not using a cast - mainly because you then needlessly introduce the possibility of a runtime error. Even though such an error can't occur with the given code, I prefer to not have the possibility at all. I do agree that my "can't" should have been "shouldn't (IMO)" - too late to edit that now though. :) – Matthew Watson Nov 13 '14 at 16:18
  • @MatthewWatson: the compiler will catch casting errors in this scenario, because it has everything it needs at compile-time to know whether the cast is valid. All a cast does here is _statically_ resolve the ambiguity. There's not even a possibility of a run-time hazard in this scenario. – Peter Duniho Nov 13 '14 at 18:42
  • For future reference to the OP: this is a very poorly-worded question. Don't make people count lines just to figure out what line of code you are talking about, and always include the specific error message you are getting, when asking about errors. – Peter Duniho Nov 13 '14 at 18:44
  • @PeterDuniho Ah - I see that you are correct. I still don't like avoidable casts though. At the very least one should add comment explaining the cast - but it would be much better to avoid it altogether IMHO. – Matthew Watson Nov 14 '14 at 09:03

2 Answers2

1

The compiler has problems trying to determine the type of your ternary operator expression, try specifying it explicitly:

Action chosenFunc = functionPicker ? (Action)SomeFunction : SomeOtherFunction;
decPL
  • 5,384
  • 1
  • 26
  • 36
1

That's because, in an expression using the ternary operator a? b : c there has to be an implicit conversion from either b to c, or c to b. Here's another example: Implicit conversion issue in a ternary condition.

In your expression, ((functionPicker == true) ? SomeFunction : SomeOtherFunction);, SomeFunction and SomeOtherFunction are method groups, and there is no implicit conversion between method groups. That is, b cannot be converted c, nor can c be converted to b.

Both method groups can, however, be converted to a delegate with no parameters and return type void, as is the case of Action. So if you cast b to Action, then there will be an implicit conversion from c to b, as @decPL demonstrated.

Community
  • 1
  • 1
dcastro
  • 66,540
  • 21
  • 145
  • 155
  • What I don't understand is that the ternary operator needs to be able to convert implicitely from `b` <-> `c`. Why not soley from `b` -> `a` and `c` -> `a`? There must be this underlying mechanism/reason,that I am still missing. To quote Jon Skeet: "It's a shame in some ways that C#'s type inference can't be more powerful". Thanks for the answer though! It certainly helps to solve it and avoid it in the future. – Mike de Klerk Nov 14 '14 at 06:18
  • @MikedeKlerk `a` is a boolean expression. You probably meant the variable to which the result will be assigned. But see, that's a completely different expression - the ternary expression and its result type are evaluated on its own, *before* the assignment expression. – dcastro Nov 14 '14 at 07:32