-1

I have this piece of code

        StateMachine.State = string.IsNullOrEmpty(MyString) ?
            (IState) StateMachine.StateA : StateMachine.StateB;

I can also write it as

        if (string.IsNullOrEmpty(MyString))
            StateMachine.State = StateMachine.StateA;
        else
            StateMachine.State = StateMachine.StateB;

State is of type IState and StateA and StateB both implement IState.

In the first snippet the compiler demands an explicit cast, while in the second it is not needed. Why is it needed in the first example?

EDIT: The suggested duplicate question doesn't completely cover my question. My question is about objects and interfaces, while the other question is about primitive data types and constant numbers. Especially the suggestion of quetzalcoatl about the declarations is very valuable.

Reading the answer on the suggested duplicate question never would have pointed me in that direction.

ffonz
  • 1,304
  • 1
  • 11
  • 29

1 Answers1

3

This happens when in expression x ? a : b the A and B return different type.

Take a look at:

double a = 5;
decimal b = 4;
var z = x ? a : b;

what should be the type of Z? Even if A and B were of some compatible type, say, int and long, how should compiler guess what to return? should the result be int, or long?

In your case, most probably, StateA is of type "classA" and StateB is of type "classB". Both classes implement IState, so simple assignement works, but when you put it into ?: operator, the compiler cannot decide whever the result of ?: operator should be classA or classB.

And yes, I'm not wrong: the compiler doesn't even consider IState. Why? Because classA and classB may have many more other common interfaces or base types. They can both implement IState, or IEnumerable, or .. object at extreme. Which common base class should compiler pick? It's hard to decide, so it does not try to guess.

There is a very simple solution to that, except for explicit casting which you already discovered on your own. Simply change the return type of StateA and StateB fields/properties.

Right now, you probably have:

class StateMachine
{
    public ClassA StateA {get .. }
    public ClassB StateB {get .. }
}

since both implement IState, just change that to:

class StateMachine
{
    public IState StateA {get .. }
    public IState StateB {get .. }
}

Furthermore, the latter way (of providing state instance just by interface), this is probably even more desirable, since if StateMachine properties are meant to be a "repository of states" to pick from, then the code-location which do choose those states probably should not know the exact implementation types of those states - but of course that's not necessary and depends on your design.

quetzalcoatl
  • 32,194
  • 8
  • 68
  • 107
  • That's it! A very good suggestion to change my declarations of StateA and StateB to IState's. Thank you very much! – ffonz Oct 04 '17 at 18:18