Expression expected in ?: operator - c#

why can't I have something like:
Some_Function ? myList.Add(a) : throw new Exception();
Why can't I throw exception in else part of ?: operator? what is the main purpose of ?: operator?
Suggestion
If anybody else wondered about the same thing, beside reading the answers below, i suggest that you read this post as well..
Expression Versus Statement

The other answers and comments are of course true (we can refer to the documentation), though my understanding of the question is more like, "why does it have to be that way?".
According to the C# 5.0 specification, the conditional operator forms an expression, not a statement. I suspect that the reason why it's not a statement, thus preventing you from doing something like a ? b() : throw e is simply because we already have a statement construct for achieving basically the same thing; namely, if..else.
if (a) { b(); } else { throw e; }
The benefit of the conditional operator is that it can be used within statements or other expressions.
bool? nb = GetValue();
if (nb ?? (a ? b() : c())) { throw e; }

Because it is defined as:
null-coalescing-expression ? expression : expression
As you can read in ?: Operator (C# Reference):
The conditional operator (?:) returns one of two values depending on the value of a Boolean expression.
One of both expression is evaluated depending on the boolean value of null-coalescing-expression.
Since neither of your two code fragments are expressions that evaluate to a value (List.Add() is void and an exception doesn't evaluate to a value either), this can't compile.

You need to remember that Ternary operator must return something and List.Add is a void method so it fails. Both the sides must be compatible and should return something.
The MSDN says:
The condition must evaluate to true or false. If condition is true,
first_expression is evaluated and becomes the result. If condition is
false, second_expression is evaluated and becomes the result.
And myList.Add(a) is not an expression.

See ?: Operator on MSDN. Its clearly explained there.
The conditional operator (?:) returns one of two values depending on the value of a Boolean expression. Following is the syntax for the conditional operator.
condition ? first_expression : second_expression;
The condition must evaluate to true or false. If condition is true, first_expression is evaluated and becomes the result. If condition is false, second_expression is evaluated and becomes the result. Only one of the two expressions is evaluated.
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.
You can express calculations that might otherwise require an if-else construction more concisely by using the conditional operator. For example, the following code uses first an if statement and then a conditional operator to classify an integer as positive or negative.
The conditional operator (?:) returns one of two values depending on the value of a Boolean expression. Following is the syntax for the conditional operator.
The condition must evaluate to true or false. If condition is true, first_expression is evaluated and becomes the result. If condition is false, second_expression is evaluated and becomes the result. Only one of the two expressions is evaluated.
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.
You can express calculations that might otherwise require an if-else construction more concisely by using the conditional operator. For example, the following code uses first an if statement and then a conditional operator to classify an integer as positive or negative.

Related

Negation of null for Nullable<bool>

I am confused with c# compiler in case of negating the null value of bool?. Compiler does interpret !null as null. My expectation is to raise
CS0266 (Cannot implicitly convert type 'bool?' to 'bool')
Sample code:
bool? nullableVal = null;
//if (nullableVal) //OK: CS0266 bool? can't be converted to bool
// ;
var expectCS0266 = !nullableVal;//No compiler error/warning
//if ((!null) ?? false)//OK: CS8310 Operator '!' cannot be applied to operands of type "<NULL>"
// ;
if (! nullableVal ?? false)
;//this statement isn't reached, because of precedence of ! is higher than ??
//and !null == null
if (!(nullableVal ?? false))
;//this statement is reached, OK
Can somebody prove why the compiler is right or vice versa.
See Section 7.3.7 of the spec:
Lifted operators permit predefined and user-defined operators that operate on non-nullable value types to also be used with nullable forms of those types. Lifted operators are constructed from predefined and user-defined operators that meet certain requirements, as described in the following:
For the unary operators
+ ++ - -- ! ~
a lifted form of an operator exists if the operand and result types are both non-nullable value types. The lifted form is constructed by adding a single ? modifier to the operand and result types. The lifted operator produces a null value if the operand is null. Otherwise, the lifted operator unwraps the operand, applies the underlying operator, and wraps the result.
(Emphasis mine)
So:
bool? x = null;
bool? y = !x;
Follows this rule. We're using the lifted form of the unary ! operator, which results in null if the value it's applied to is null.
!null isn't allowed, because null isn't of type Nullable<T>. !(bool?)null works, however (although it produces a compiler warning).
! indeed has higher precedence than ??, see Section 7.3.1

equality and null check (Ruby-on-Rails and c#)

I was using the ||= operator in Ruby on Rails and I saw that C# have something similar.
Is ||= in Ruby on Rails equals to ?? in C# ?
What is the difference if there is one?
Based on what I have read here, the x ||= y operator works like:
This is saying, set x to y if x is nil, false, or undefined. Otherwise set it to x.
(modified, generalized, formatting added)
The null-coalescing operator ?? on the other hand is defined like:
The ?? operator is called the null-coalescing operator. It returns the left-hand operand if the operand is not null; otherwise it returns the right hand operand.
(formatting added)
Based on that there are two important differences:
The ?? does not assign, it is like a ternary operator. The outcome can be assigned, but other things can be done with it: assign it to another variable for instance, or call a method on it; and
The ?? only checks for null (and for instance not for false), whereas ||= works with nil, false and undefined.
But I agree they have some "similar purpose" although || in Ruby is probably more similar with ??, but it still violates (2).
Also mind that the left part of the null-coalescing operator does not have to be a variable: on could write:
Foo() ?? 0
So here we call a Foo method.
Simple answer... yes and no.
The purpose of the ||= operator in Ruby-on-Rails is to assign the left-hand operand to itself if not null, otherwise set it to the the right-hand operand.
In C#, the null coalescing operator ?? makes the same check that ||= does, however it's not used to assign. It serves the same purpose as a != null ? a : b.

Safe Navigation Operator with Any()

Hey Everyone I thought that this code would be valid in any case because it is casted to bool
parameter.Request?.InnerData?.Any() == false
Instead this code is casted to type bool?
Can tell me someone why? (this is main question)
Is there better way to check this instead of something like this?
var isThereInnerData = parameter.Request?.InnerData?.Any();
if (isThereSegments == null || isThereSegments == false)
With a null-conditional operator, null propagates. You can't end up with a non-nullable type if you use the null-conditional operator - this is the same behaviour in languages where null operations are "safe" by default (SQL, Objective-C, ...). So the result is default(bool?) if parameter.Request is null, or parameter.Request.InnerData is null. Otherwise, you get true or false, but by using the null-conditional operator you already assume the result can in fact be null, so the compiler must accomodate that. Since bool can't be null, it is changed into a nullable bool (bool?).
The solution is simple - think about what logical value a null should have, and use that:
if (parameter.Request?.InnerData?.Any() ?? true)
In this case, a null value is interpreted as true, but you can also use false if you want. Alternatively, instead of the null-coalescing operator, you can use GetValueOrDefault, whatever feels better for you.
Here is what C# reference says about ?. operator:
x?.y – null conditional member access. Returns null if the left hand
operand is null.
Since at compile time the compiler doesn't knows whether the expression will evaluate to a non-null value, the compiler infers the type as Nullable<bool>
Since you are chaining the ?. operator this line from msdn documentation is relevant too:
The null-condition operators are
short-circuiting. If one operation in a chain of conditional member
access and index operation returns null, then the rest of the chain’s
execution stops. Other operations with lower precedence in the
expression continue. For example, E in the following always executes,
and the ?? and == operations execute.
bool is a value type and per default cannot be compared with null. C# converts your return value to bool? to give you the option to support both.

Doubts about the 'var' keyword and ternary operator ?:

If var keyword is resolved at compile time, how does the following work?
class A {
}
class B : A {
}
int k = 1;
var x = (k < 0) ? new B() : new A();
Edit:
I finally understood that the problem is not about the var itself, but about the behaviour of the ?: operator. For some reason, I thought that the following could be possible:
object x = something ? 1 : ""
and that's not possible at all :)
Related question (about ternary operator):
Why assigning null in ternary operator fails: no implicit conversion between null and int?
The result is of type A, because both of the variables are of type A, and at least one of them is directly of type A (not through some conversion).
The compiler takes a look at both parts of the ternary expression, and if one of them is a subtype of the other, the entire expression becomes the more general supertype.
However, if neither is directly of the common type, then a compiler error occurs, probably because it doesn't know how much to upcast for you (and it doesn't feel like finding out).
See here:
The conditional operator (?:) returns one of two values depending on the value of a Boolean expression. Following is the syntax for the conditional operator.
condition ? first_expression : second_expression;
[...]
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.
The result is A. An easy way to confirm it is to place your mouse over the var.
I haven't tested this degenerate case. But I would bet either (1) compiler complains or (2) 'x' is of type 'A'.

?? Operator with 2 strings?

In this .NET code:
return Redirect("~/Home" ?? "JaneDoe");
If I'm reading the docs right, the "??" operator appears to operate similarly to IsNull in SQL:
IsNull("~/Home", "JaneDoe")
"~Home" and "JaneDoe" are simply strings, right? There's no condition in the return Redirect code where "JaneDoe" will be what's passed into "Redirect", is there? I'm not sure what to make of this snippet, I can only presume it's a placeholder for something to come later.
This code is from a .NET-MVC project in development, part of a .cs file that is a LoginController.
Yes, this is just bad code. That will always be equivalent to
return Redirect("~/Home");
I'm slightly surprised the compiler isn't smart enough to give a warning about it, to be honest. It would be nice if it could tell that a constant non-null expression was being used on the LHS of the null-coalescing operator.
The ?? operator is called the null-coalescing operator and is used to define a default value for a nullable value types as well as reference types. It returns the left-hand operand if it is not null; otherwise it returns the right operand.
In your case, it will never return JaneDoe
Yes, you're reading it correctly. That will always return "~/Home", presumably it was planned to change it to a variable at some point.
This would always use the "~/Home" string. The null-coalescing operator (??) selects the left side if it is non-null, or the right side if it is null.
Correct, the expression will never return "JaneDoe".

Categories

Resources