Coalescing operator vs Ternary operator [duplicate] - c#

This question already has answers here:
Conditional operator assignment with Nullable<value> types?
(6 answers)
Why doesn't this C# code compile?
(4 answers)
Closed 9 years ago.
I just came across a weird error:
private bool GetBoolValue()
{
//Do some logic and return true or false
}
Then, in another method, something like this:
int? x = GetBoolValue() ? 10 : null;
Simple, if the method returns true, assign 10 to the Nullableint x. Otherwise, assign null to the nullable int. However, the compiler complains:
Error 1 Type of conditional expression cannot be determined because there is no implicit conversion between int and <null>.
Am I going nuts?

The compiler first tries to evaluate the right-hand expression:
GetBoolValue() ? 10 : null
The 10 is an int literal (not int?) and null is, well, null. There's no implicit conversion between those two hence the error message.
If you change the right-hand expression to one of the following then it compiles because there is an implicit conversion between int? and null (#1) and between int and int? (#2, #3).
GetBoolValue() ? (int?)10 : null // #1
GetBoolValue() ? 10 : (int?)null // #2
GetBoolValue() ? 10 : default(int?) // #3

Try this:
int? x = GetBoolValue() ? 10 : (int?)null;
Basically what is happening is that conditional operator is unable to determine the "return type" of the expression. Since the compiler implictitly decides that 10 is an int it then decides that the return type of this expression shall be an int as well. Since an int cannot be null (the third operand of the conditional operator) it complains.
By casting the null to a Nullable<int> we are telling the compiler explicitly that the return type of this expression shall be a Nullable<int>. You could have just as easily casted the 10 to int? as well and had the same effect.

Try this:
int? result = condition ? 10 : default(int?);

Incidentally, the Microsoft implementation of the C# compiler actually gets the type analysis of the conditional operator wrong in a very subtle and interesting (to me) way. My article on it is Type inference woes, part one (2006-05-24).

Try one of these:
int? x = GetBoolValue() ? (int?)10 : null;
int? x = GetBoolValue() ? 10 : (int?)null;

The problem is that the ternary operator is inferring type based on your first parameter assignment...10 in this case, which is an int, not a nullable int.
You might have better luck with:
int? x = GetBoolValue() (int?)10 : null;

int? x = GetBoolValue() ? 10 : (int?)null;
The reason you see this is because behind the scenes you're using Nullable and you need to tell C# that your "null" is a null instance of Nullable.

Just add an explict cast.
int? x = GetBoolValue() ? 10 : (int?)null;
It is the ternary operator that gets confused - the second argument is an integer and so is the third argument exspected to be an integer, too, and null does not fit.

It's because the compiler determines the type of the conditional operator by its second and third operand, not by what you assign the result to. There is no direct cast between an integer and an null reference that the compiler can use to determine the type.

Related

differences between the conditional operator and an if-else:

I read this question and I found Tim Schmelter's answer:
By the way, that's one of the differences between the conditional operator and an if-else
you can check the answer for this question, and I can't found the reason ?
if conditional operator work like if-else why if else don't need the cast
question :
int? l = lc.HasValue ? (int)lc.Value : null;
"Tim Schmelter" answer :
You have to cast null as well:
int? l = lc.HasValue ? (int)lc.Value : (int?)null;
By the way, that's one of the differences between the conditional operator and an if-else:
if (lc.HasValue)
l = (int)lc.Value;
else
l = null; // works
The literal null alone does not have a type, but it is implicitly convertible to any reference type and to any Nullable<> type. In the expression:
x = null
where x is assigned to null, the compiler can easily infer from the type of the variable (or field or property or parameter or whatever) x what the null literal shall be converted into. For example if x is of type string, the null shall represent the null reference, while if x is of type int?, the null shall represent an instance of Nullable<int> where HasValue is false.
If x is of type int, no implicit conversion exists, and the above expression shall not compile.
(The declaration var x = null; with var is not legal since null has no type in itself.)
On the other hand, in the expression:
someBoolean ? 42 : null /* illegal */
the compiler cannot figure out what type to convert null into. Remember that int is neither reference type, nor Nullable<> type.
If you meant wrapping into a nullable, use:
someBoolean ? (int?)42 : null
or:
someBoolean ? 42 : (int?)null
In both cases the compiler will automatically see that the other operand (on the other side of the colon :) must also be implicitly converted to int?.
If you meant boxing into some base class or interface of int, write that:
someBoolean ? (object)42 : null
or:
someBoolean ? 42 : (object)null
Now, the expressions above could be sub-expressions of a greater containing expression, but the compiler will still need the type of the ?: expression to be clear by itself. For example in:
int? x;
x = someBoolean ? 42 : null; // still illegal!
even if the sub-expression someBoolean ? 42 : null appears inside a larger expression x = someBoolean ? 42 : null where x does have a type, the sub-expression must still acquire its type "intrinsically". The type of x cannot "leak onto" the sub-expression. This "grammar" seems to be a surprise to many new C# developers. Questions like yours are often seen, see e.g. Nullable type issue with ?: Conditional Operator and the threads linked to it.
The if statement doesn't yield a value, so the statements in the "then" and "else" parts don't need to be type compatible in any way.
The conditional operator yields a value, and therefore both parts must be type compatible in some way in order for the compiler to determine the type of the expression.
MSDN says for the conditional operator :
*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.*
This is the reason. In the if-else constructor the code in else block is independent from the code in if block so the type-casting can be inferred by the compiler in each case.

Why must I cast to (int?) in C# when variable type is [int?]

Can someone please explain me the logic reason why I must cast null to int?
When the left argument type can have their both types ?
Insted of doing
int? k = (DateTime.Now.Ticks%5 > 3 ? 1 : null);
I must do
int? k = (DateTime.Now.Ticks%5 > 3 ? 1 : (int?) null);
although int? k = null is perfectly valid.
An opposite example :
I didn't have to do it in:
string k = (DateTime.Now.Ticks%5 > 3 ? "lala" : null);
int? k = (DateTime.Now.Ticks%5 > 3 ? 1 : (int?) null);
In this case what we have is 1 is int and null is actually null
Now the confusion is the ternary operator is confused as what is the return type int or well null and since its int it won't accept null
So you would need to cast it to a nullable int
Now in the other case you have a string and null is perfectly acceptable for a string
Further explanation can be found at Type inference - Eric
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 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 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.
Because the compiler doesn't use the type of the variable in the left hand side to determine the type of the expression on the right hand side. First it determines what type the expression is, then it determines if it's possible to put it in the variable.
There is no type close enough that is common between an int and a null value. You have to either make the int value nullable or the null value "intable" for the compiler to find a common ground for the values.
When you have a string and a null value the compiler can simply use one of the types, because a string is already nullable.

C# conditional operator ?: has problems with nullable int [duplicate]

This question already has answers here:
Closed 10 years ago.
Possible Duplicate:
Conditional operator assignment with Nullable<value> types?
Why does the conditional operator “?:” not work here when my function is returning a nullable integer “int?”? “return null” works but with “?:” I have to cast “null” to “(int?)” first.
public int? IsLongName(string name) {
int length = name.Length;
// this works without problems
if (name.Length > 10) {
return null;
} else {
return name.Length;
}
// this reports:
// Type of conditional expression cannot be determined because
// there is no implicit conversion between '<null>' and 'int'
return name.Length > 10 ? null : name.Length;
}
Try changing your last line to this:
return name.Length > 10 ? null : (int?)name.Length;
The compiler can't understand what's the return type of the ?: operator. It has conflicting values - null and int. By casting the int to nullable, the compiler can understand the return type is nullable int, and null would be accepted as well.
Both a null value and an int value can be implicitly converted to an int? data type, but a literal of null on its own isn't known by the compiler to be anything other than an object if you don't tell it. There is no common data type that both object and int can be implicitly converted to, which is what the compiler is complaining about.
As Yorye says, you can cast the int to int? to let the compiler do the conversion; or, you can cast the null to int?, which then allows the compiled to use the implicit conversion from int to int?.
Both conditions of the ?: operator must be implicitly compatible. int can never be null, so there is a compile-time error (likewise, null can never be int). You have to cast, there's no way around it using the ternary.
I don't think you would have the same problem with an if statement, because the compiler would only check that the method returns a compatible value to the return type from any given path, not that the return value from any given exit point is implicitly compatible with another block's return value.
The ?: operator only considers the types of its two possible return values. It is not aware of the type of the variable that will receive its result (indeed, in more complex expressions, no explicit variable may exist).
If one of those return values is null, it has no type information - it can only check the other return value's type, and check whether a conversion exists.
In your case, we have null and a return value of type int. There is no conversion available. There would be a conversion to int?, but that is neither of the possible return types that ?: is considering.

Why can't I set a nullable int to null in a ternary if statement? [duplicate]

This question already has answers here:
Conditional operator cannot cast implicitly?
(3 answers)
Closed 9 years ago.
The C# code below:
int? i;
i = (true ? null : 0);
gives me the error:
Type of conditional expression cannot
be determined because there is no
implicit conversion between '<null>'
and 'int'
Shouldn't this be valid? What am i missing here?
The compiler tries to evaluate the right-hand expression. null is null and the 0 is an int literal, not int?. The compiler is trying to tell you that it can't determine what type the expression should evaluate as. There's no implicit conversion between null and int, hence the error message.
You need to tell the compiler that the expression should evaluate as an int?. There is an implicit conversion between int? and int, or between null and int?, so either of these should work:
int? x = true ? (int?)null : 0;
int? y = true ? null : (int?)0;
You need to use the default() keyword rather than null when dealing with ternary operators.
Example:
int? i = (true ? default(int?) : 0);
Alternately, you could just cast the null:
int? i = (true ? (int?)null : 0);
Personally I stick with the default() notation, it's just a preference, really. But you should ultimately stick to just one specific notation, IMHO.
HTH!
The portion (true ? null : 0) becomes a function in a way. This function needs a return type. When the compiler needs to figure out the return type it can't.
This works:
int? i;
i = (true ? null : (int?)0);

c# why can't a nullable int be assigned null as a value [duplicate]

This question already has answers here:
Conditional operator assignment with Nullable<value> types?
(6 answers)
Nullable types and the ternary operator: why is `? 10 : null` forbidden? [duplicate]
(9 answers)
Closed 9 years ago.
Explain why a nullable int can't be assigned the value of null e.g
int? accom = (accomStr == "noval" ? null : Convert.ToInt32(accomStr));
What's wrong with that code?
The problem isn't that null cannot be assigned to an int?. The problem is that both values returned by the ternary operator must be the same type, or one must be implicitly convertible to the other. In this case, null cannot be implicitly converted to int nor vice-versus, so an explict cast is necessary. Try this instead:
int? accom = (accomStr == "noval" ? (int?)null : Convert.ToInt32(accomStr));
What Harry S says is exactly right, but
int? accom = (accomStr == "noval" ? null : (int?)Convert.ToInt32(accomStr));
would also do the trick. (We Resharper users can always spot each other in crowds...)
Another option is to use
int? accom = (accomStr == "noval" ? Convert.DBNull : Convert.ToInt32(accomStr);
I like this one most.
Similarly I did for long:
myLongVariable = (!string.IsNullOrEmpty(cbLong.SelectedItem.Value)) ? Convert.ToInt64(cbLong.SelectedItem.Value) : (long?)null;

Categories

Resources