astellin
astellin

Reputation: 443

weird compiler error when casting in ternary/conditional operator

I'm experiencing unexpected compiler errors with this code:

bool b = true; //or false
StringBuilder builder = ...; // a string builder filled with content
IVersePart vp = b ? (DualLanguageVersePart)builder : (VersePart)builder;

Both DualLanguageVersePart and VersePart implement the IVersePart interface. Both DualLanguageVersePart and VersePart have an explicit cast operator form StringBuilder.

Since both classes implement the interface that's the type of vp, I would expect this to work flawlessly, or at least compile properly. Instead the compiler reports that no implicit conversion can be done between the two types.

Why is this not working?

Upvotes: 1

Views: 190

Answers (6)

Ben Voigt
Ben Voigt

Reputation: 283664

The result type of any operator (other than operator implicit) is determined by the operands and not by context.

Contrary to most of the wisdom being dispensed here, both arguments don't have to be the same type. If one type is derived from the other then the ternary operator result will be the base type. But in your example there are multiple common base types: at least Object and IVersePart, and the C# language doesn't make the compiler try to figure out which is better.

Upvotes: -1

James Curran
James Curran

Reputation: 103515

This is a bad design. Cast operators should not be used like that.

It would be better to have a ctor to handle this (as you are, in fact trying to construct a new object)

IVersePart vp = new DualLanguageVersePart(builder);

Alternately, you could use a factory:

IVersePart vp = VersePart.DualOrSingluar(builder, b);

Upvotes: 2

Jerod Houghtelling
Jerod Houghtelling

Reputation: 4867

The ternary operate requires the true and false to return the same type. Here's is one way to get around this, kind of sloppy though...

IVersePart vp = b 
    ? (IVersePart)((DualLanguageVersePart)builder) 
    : (IVersePart)((VersePart)builder); 

Upvotes: 0

Matt Greer
Matt Greer

Reputation: 62027

The ternary operator needs to be able to return one type, as it's just a single statement. So when you have the two parts of the operator returning different types, the compiler will attempt to allow this by quietly converting one to the other. You don't have a conversion from DualLanguageVersePart to VersePart, or vice versa.

One simple fix is to just add in a second cast to IVersePart:

IVersePart vp = b ? (IVersePart)(DualLanguageVersePart)builder : (IVersePart)(VersePart)builder;

Upvotes: 0

Blindy
Blindy

Reputation: 67380

Both parts have to have the same type, so try this:

IVersePart vp = b ? 
  (IVersePart)(DualLanguageVersePart)builder :
  (IVersePart)(VersePart)builder;

The C# compiler is fussier about this than the C++ compiler :)

Upvotes: 2

Jimmy Hoffa
Jimmy Hoffa

Reputation: 5967

I've had this issue before, ternary operator requires both types of the true result or false result either be the same type, or you cast them to the same type.

Upvotes: 1

Related Questions