This question already has answers here:
Why does >= return false when == returns true for null values?
(8 answers)
How to compare nullable types?
(8 answers)
nullable bool in if() statement - checks required?
(5 answers)
Closed 2 years ago.
Can someone explain to me why this works?
List<int> foo = null;
bool bar = foo?.Count > 7;
When foo is null, it becomes equivalent to the following:
bool bar = null > 7;
The IntelliSense is saying both null and 7 are of type Nullable<int>, but how did the compiler decide that?!
Additionally, Nullable<T> doesn't define a greater than operator. How could it? There is no guarantee that T defines a greater than operator.
As Rofus and Jeroin correctly pointed out in comments the conversion between T to T? is always implicit when you do the comparison with "Null" 7 becomes a "Nullable<int>"
bool bar = foo?.Count > 7;
is similar to -
int? count = null;
int? k = 7; // Implicit conversion here!
var bar = count > k;
For your second question on the > operator. Yes, while the Nullable<T> struct does not define operators such as <, >, or even ==, still the following code compiles and executes correctly which is similar to your case -
int? x = 3;
int? y = 10;
bool b = x > y;
This is because compiler lifts the greater than operator from underlying value type like -
bool b = (x.HasValue && y.HasValue) ? (x.Value > y.Value) : false;
Operator Lifting or Lifted Operators means you can implicitly use T's operators on T?. Compiler has different set of rules on different set of operators on handling them on Nullable<T> types.
Related
This question already has answers here:
Nullable types and the ternary operator: why is `? 10 : null` forbidden? [duplicate]
(9 answers)
Closed 5 years ago.
int a = 1;
int? b = a;
Console.WriteLine(b);
The above snippet is fine and will convert int directly to int?, no explicit conversion is required
but
List<int> temp = new List<int>{1};
int? valueVariable = temp!=null && temp.Count>0 ? temp[0] : null ;
Console.WriteLine(valueVariable);
will have compile time error.
to fix this We need to cast to int?
// Working Snippet with int? casting
int? valueVariable = temp!=null && temp.Count > 0 ? (int?) temp[0] : null ;
https://dotnetfiddle.net/0x7ckL
Why we needed casting here,although the same was working for first example?
The reason is that ternary operator must use the SAME type in both branches. So true and false return values must be either int? or int. Cannot use two different types.
This question already has answers here:
Nullable type issue with ?: Conditional Operator
(5 answers)
Closed 5 years ago.
I can sometimes assign null to int? but not inside a ? : , why?
example
int? a; // good
int? b; // good
a = null; // why is this allowed?
b = (a != null) ? 1 : null /* and this not allowed? */;
b = (a != null) ? 1 : (int?)null /* this is a fix */;
From the documentation:
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.
So, in b = (a != null) ? 1 : null type of first argument is int, and second argument is null, which violates the above rule.
In the second case, int can be implicitly converted to (int?)null, that's why it works.
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.
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 8 years ago.
I have this property:
int? firstClientID;
Why does this
firstClientID = dataRow.IsFirstClientIDNull()
? null
: (int.TryParse(dataRow.FirstClientID, out tempInt)
? tempInt
: 0);
not compile because
type of conditional statement cannot be determined since there is no
implicit conversion between null and int
and does
if (dataRow.IsFirstClientIDNull())
firstClientID = null;
else if (int.TryParse(dataRow.FirstClientID, out tempInt))
firstClientID = tempInt;
else
firstClientID = 0;
work? They seem to do the same thing.
From MSDN
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.
i.e. You will need to ensure both legs of the conditional operator return the same type (i.e. cast through Nullable<int>).
firstClientID = dataRow.IsFirstClientIDNull()
? (int?)null
: (int.TryParse(dataRow.FirstClientID, out tempInt)
? tempInt
: 0);
(The conditional operator is not really the same as an if / then else branch, as the conditional operator must return data of the same type, whereas if can do anything in each leg of the branches, with no constraints on type compatability)
This question already has answers here:
Closed 10 years ago.
Possible Duplicate:
C# okay with comparing value types to null
I came a cross something I find strange in the C# (4.0) compiler just now.
int x = 0;
if (x == null) // Only gives a warning - 'expression is always false'
x = 1;
int y = (int)null; // Compile error
int z = (int)(int?)null; // Compiles, but runtime error 'Nullable object must have a value.'
If you cannot assign null to an int, why does the compiler allow you to compare them (It gives a warning only)?
Interestingly, the compiler does not allow the following:
struct myStruct
{
};
myStruct s = new myStruct();
if (s == null) // does NOT compile
;
Why does the struct example not compile, but the int example does?
When the comparison is made, the compiler tries to make it so both operands of the comparison have compatible types if possible.
It had an int value and a constant null value (with no particular type). The only compatible type between the two values is int? so they are coerced to int? and compared as int? == int?. Some int value as an int? is definitely non-null and null is definitely null. The compiler realizes that and since a non-null value is not equal to a definite null value, the warning is given.
actually compilation allow comparing 'int?' to 'int' not 'int' to null which make sense
e.g.
int? nullableData = 5;
int data = 10;
data = (int)nullableData;// this make sense
nullableData = data;// this make sense
// you can assign null to int
nullableData = null;
// same as above statment.
nullableData = (int?)null;
data = (int)(int?)null;
// actually you are converting from 'int?' to 'int'
// which can be detected only at runtime if allowed or not
and that's what you are trying to do in int z = (int)(int?)null;