No implicit conversion when using conditional operator [duplicate]

I have following classes:

abstract class AClass { }
class Foo : AClass { }
class Bar : AClass { }

And when I am trying to use them:

AClass myInstance;
myInstance = true ? new Foo() : new Bar();

This code won't compiling because of the "Type of conditional expression cannot be determined because there is no implicit conversion between 'CSharpTest.Class1.Foo' and 'CSharpTest.Class1.Bar'"

But following samples compiling ok:

if (true)
{
    myInstance = new Foo();
}
else
{
    myInstance = new Bar();
}

This is ok too:

myInstance = true ? (AClass) new Foo() : new Bar();

or

myInstance = true ? new Foo() : (AClass) new Bar();

Why there is so big difference in behavior of the conditional operator and if clause?


Solution 1:

This is the expected behavior.

Since no implicit conversion exists between X and Y (even if they share a common base, there is no implicit conversion between them), you need to explicitly cast (at least) one of them to the base class so that an implicit conversion exists.

A detailed explanation from the C# specification:

The second and third operands of the ?: operator control the type of the conditional expression. Let X and Y be the types of the second and third operands. Then,

If X and Y are the same type, then this is the type of the conditional expression.

Otherwise, if an implicit conversion (Section 6.1) exists from X to Y, but not from Y to X, then Y is the type of the conditional expression.

Otherwise, if an implicit conversion (Section 6.1) exists from Y to X, but not from X to Y, then X is the type of the conditional expression.

Otherwise, no expression type can be determined, and a compile-time error occurs.

Solution 2:

There's not really a big difference in the ternary operator vs the if clause, its a difference in your statements.

In your first working example, you're converting between Foo and AClass or Bar and AClass, which is obviously fine.

In your second working example, you're telling the ternary operator to look at AClass and Bar. In the third working example, you're telling the ternary operator to look at Foo and AClass. Those obviously have obvious conversions.

In the non-working example, you're telling it to look at Foo and Bar. There's no implicit conversion there (because one doesn't derive from the other, for example). But you can go ahead and be explicit about it and cast it (which is what you do in the 2nd and 3rd working examples) since there is a conversion available.