This works:
short value;
value = 10 > 4 ? 5 : 10;
This works:
short value;
value = "test" == "test" ? 5 : 10;
This doesn't work:
short value;
string str = "test";
value = "test" == str ? 5 : 10;
Neither does this:
short value;
string str = "test";
value = "test".Equals(str) ? 5 : 10;
The last two cases I am getting the following error:
Cannot implicitly convert type 'int' to 'short'.
An explicit conversion exists (are you missing a cast?)
Why do I have to cast on the last two cases and not on the two first cases?
The using statement causes the object itself to go out of scope as soon as Dispose is called. Within the using block, the object is read-only and can't be modified or reassigned. A variable declared with a using declaration is read-only.
CSharp Online Training The using statement is used to set one or more than one resource. These resources are executed and the resource is released. The statement is also used with database operations. The main goal is to manage resources and release all the resources automatically.
Get started with C. Official C documentation - Might be hard to follow and understand for beginners. Visit official C Programming documentation. Write a lot of C programming code - The only way you can learn programming is by writing a lot of code.
short value;
value = 10 > 4 ? 5 : 10; //1
value = "test" == "test" ? 5 : 10; //2
string str = "test";
value = "test" == str ? 5 : 10; //3
value = "test".Equals(str) ? 5 : 10; //4
The last two ternary expressions (3,4) cannot be resolved to a constant at compile time. Thus the compiler treats the 5
and 10
as int
literals, and the type of the entire ternary expression is int
. To convert from an int
to a short
requires an explicit cast.
The first two ternary expressions (1,2) can be resolved to a constant at compile time. The constant value is an int
, but the compiler knows it fits in a short
, and thus does not require any casting.
For fun, try this:
value = "test" == "test" ? 5 : (int)short.MaxValue + 1;
You need a cast to make the two last examples work
value = (short)("test" == str ? 5 : 10);
Why dont't you need it in the first two?
Because the first two are compile-time constants. The compiler is able to translate 10 > 4 ? 5 : 10
to true ? 5 : 10
, then to just 5
So when you write
value = 10 > 4 ? 5 : 10;
It's effectively the same as
value = 5;
which compiles because the compiler is allowed to implicitly cast constants if they are in the allowed range.
Conversely, "test" == str ? 5 : 10;
is not a compile time constant, so the compile is not allowed to implcitly cast it. You need to make an explicit cast yoursef.
This is defined by the C# Language Specification, of course.
The key thing to be aware of is that there are two kinds of conversions from int
to short
. One is an explicit conversion which always applies but which requires you to write (short)
explicitly before the int
expression. The other one is an implicit constant expression conversion which only applies when (a) the int
expression is a compile-time constant and (b) the value of this compile-time expression is within the range of a short
, that is -32768
through 32767
.
A literal like 5
, 10
or 4
has type int
in C# (that goes for any integer literal which is between -2147483648
and 2147483647
and not followed by a symbol L
, U
or similar). So if we look at the right-hand sides of all your assignments, they are clearly int
expressions, not short
.
In the case 10 > 4 ? 5 : 10
, since 10
and 4
are compile-time constants, this is the same as true ? 5 : 10
because the >
operator between int
s is built-in and will result in a constant when the operands are constants. And in the same way true ? 5 : 10
gives 5
because all three operands are constants, and ?:
is classified a constant itself in that case. So it really says:
short value = 5;
where the "5
" is a compile-time constant. Hence it is checked at compile-time if the int
5
is within the range (it does not matter with the 10
, it could be 999999
), and since that is the case, the implicit constant expression conversion applies, and it is legal.
Note that you can do the same with:
const int huge = 10;
const int tiny = 4;
const int significant = 5;
const int unimporatnt = 10;
short value;
value = huge > tiny ? significant : unimportant;
as long as all the operands are const
variables (pun?).
Now, if I managed to make the explanation clear, you will also know by now that the obstacle preventing value = "test" == str ? 5 : 10;
from working is that you did not mark the str
local as const
. Do that, and it will be allowed.
With the Equals
call, things are a bit worse. The result of a call to Equals
is never considered a compile-time constant (and I don't think it is "optimized" away, for example "same".Equals("same")
will actually call the method at run-time). Same thing would happen with (10).Equals(4)
or (10).CompareTo(4) > 0
and so on, so strings are not special in this respect.
Most likely you know already that when
short value = cond ? 5 : 10;
is not allowed because cond
is not a compile-time constant, you just use the explicit conversion instead, so write:
short value = cond ? (short)5 : (short)10;
or:
short value = (short)(cond ? 5 : 10);
Technically, they are not identical, since the first one has no narrowing conversion at run-time (the expressions (short)5
and (short)10
are literals of type short
), while the last one has to convert an int
to short
at run-time (which is of course cheaper than incredibly cheap).
The other (non-deleted!) answers are correct, this is just bonus information.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With