Click here to Skip to main content
15,886,362 members
Please Sign up or sign in to vote.
4.00/5 (1 vote)
Why do I need explicit cast in this case:
C#
class Program
    {

        static void Main()
        {
            bool boolVal = true;
            Animal a = boolVal ? new Dog() : new Cat();
        }

    }

    class Animal { }

    class Dog : Animal { }

    class Cat : Animal { }



At this line: "Animal a = boolVal ? new Dog() : new Cat();" I will get a compiler error "Type of conditional expression cannot be determined because there is no explicit conversion between Dog and Cat".
But If I add a cast to animal before "new Dog()" the compiler doesn't complain. Don't I also need to cast the second expression ? What's this strange behavior? :headache:

Also the same is the case with value types:
C#
static void Main()
        {
            bool randomBool = true;
            short someRandomVal = 5;

            short s = randomBool ? someRandomVal : 0; // Won't work
        }


However here I need to cast the second value not the first value because the first is already a short.

What I have tried:

Looking at the documentation for ternary operator however I didn't see anything related to this behavior there.
Posted
Updated 1-Apr-18 0:38am
v2
Comments
[no name] 1-Apr-18 5:42am    
That you will find under Remark in the MS Docs:
"Either the type of first_expression and second_expression must be the same, or an implicit conversion must exist from one type to the other."
[no name] 1-Apr-18 6:42am    
Btw, both of them will compile:
Animal a = boolVal ? (Animal)new Dog() : new Cat();
Animal a = boolVal ? new Dog() : (Animal)new Cat();

Most likely a shortcoming of the compiler processor, i.e. the compiler takes one side of the ':' as the output type (probably the left) and assumes the second (right) must match otherwise throws and error without checking the inheritance tree in the case of Dog and Cat and the left side of the expression being an Animal.

In the second case the s is a short but the 0 value is assumed an int by default and you get a cast exception.
 
Share this answer
 
Comments
The_Unknown_Member 1-Apr-18 5:59am    
Is this behavior only happening with ternary operators?
Mehdi Gholam 1-Apr-18 9:46am    
Can't say.
BillWoodruff 1-Apr-18 9:35am    
"Most likely a shortcoming of the compiler processor,"

Most likely by design :)
When you specify the return Type, and the ternary values that may be returned are of different Types, the compiler must check if a Type conversion is possible.

These work because the compiler can determine there is a conversion possible:
bool boolVal = true;
Animal a1 = boolVal ? new Dog() : (Animal) new Cat();
Animal a2 = boolVal ? (Animal) new Dog() : new Cat();
With your example using Type 'short: what you observe is partly due to the fact that 'short has no literal character that can be appended to it to indicate the Type, as other integral Types allow ... like 'u or 'U for UInt or ULong: [^].

These work:
bool randomBool = true;
short someRandomVal = 5;

var s1 = randomBool ? 0 : someRandomVal; // return Type is Int32

var s2 = randomBool ? someRandomVal : 0; // return Type is Int32

short s3 = randomBool ? someRandomVal : (short) 0; // return Type is Int16

Int32 s4 = randomBool ? someRandomVal : 0;
Int32 s5 = randomBool ? 0 : someRandomVal;
Keep in mind that an integral numeric value can always be converted/represented to/in an integral Type with "more precision" ... i.e., more bits, greater range ... without loss of information.
 
Share this answer
 
Comments
Mehdi Gholam 1-Apr-18 9:46am    
5'ed
BillWoodruff 1-Apr-18 10:08am    
Thanks, Mehdi !

This content, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)



CodeProject, 20 Bay Street, 11th Floor Toronto, Ontario, Canada M5J 2N8 +1 (416) 849-8900