Ternary operator VB vs C#: why resolves Nothing to zero?
This is because VB's Nothing
is not a direct equivalent to C#'s null
.
For example, in C# this code will not compile:
int i = null;
But this VB.Net code works just fine:
Dim i As Integer = Nothing
VB.Net's Nothing
is actually a closer match for C#'s default(T)
expression.
VB.NET - Nullable DateTime and Ternary Operator
I will admit that I'm not an expert on this, but apparently it stems from two things:
- The
If
ternary operator can return only one type, in this case a date type, not a nullable date type - The VB.Net
Nothing
value is not actuallynull
but is equivalent to the default value of the specified type, in this case a date, not a nullable date. Hence the date minimum value.
I derived most of the information for this answer from this SO post: Ternary operator VB vs C#: why resolves to integer and not integer?
Hope this helps and that someone like Joel Coehoorn can shed more light on the subject.
if() operator/function bugs dealing with nothing. IF() doesn't return nothing. Why?
The If
operator can be thought of as being like a generic function:
If(Of T)(condition As Boolean,
truePart As T,
falsePart As T) As T
That means that the second and third arguments must be the same type (either explicitly or one can be cast as the other) and the return value will be that same type. With that in mind, let's look at some of your examples.
'2nd msgbox. If(D, Nothing, True) returns false instead of nothing
MsgBox(If(D, Nothing, True), vbOK, "'2nd msgbox.")
So, for that to work at all, the second and third as the same type. What type could that possibly be? The type of the second argument is unspecified while the type of the third is Boolean
. Nothing
can be cast as type Boolean
so that's what happens, and the return value is thus also Boolean
. Casting Nothing
as type Boolean
yields False
, so the second argument is effectively False
and that's what gets returned.
Dim UnevaluatedPart As Nullable(Of Integer)
' 8th. Now it returns nothing with integer? as third argument (false part)
MsgBox(If(True, Nothing, UnevaluatedPart), vbOK, "8th. Now it returns nothing")
' 9th. Proof of above (it's really nothing not empty string ""
MsgBox(If(True, Nothing, UnevaluatedPart) Is Nothing, vbOK, "' 9th. Proof of above")
In both these cases, the type of the second parameter is unspecified and the type of the third parameter is Integer?
so Nothing
gets cast as type Integer?
. That means that both the second and third arguments are a Integer?
with no value. You're going to get the same return value whether the condition is True
or False
. Of course it won't be an empty String
because the return value MUST be type Integer?
. It's not just Nothing
though; it's a Integer?
with no value, so you can actually test the HasValue
property of that result.
' 5th. this returns different result (int format) but again not the expected nothing
MsgBox(If(True, Nothing, 15), vbOK, "5th.")
Again, the type of the second argument is unspecified so the argument and return type is inferred from the third argument. That third argument is type Integer
so that means that Nothing
is cast as type Integer
, which yields zero. The condition is True
so it is that zero value that gets returned. If you tested whether that was equal to Nothing
then you'd find that it is, which is exactly why that's what Nothing
got converted to for the second parameter.
Is there a VB.NET expression that *always* yields null?
The first answer I gave missed some points, but this should do it:
Dim o As Object = If(myBool, 5, DirectCast(Nullable.GetUnderlyingType(GetType(Integer)), Object))
This uses the fact that Nullable.GetUnderlyingType
will return a null reference if you pass it a type which isn't a nullable value type - which Integer
isn't. Other alternatives exist, such as Type.GetElementType()
, or perhaps GetType(Object).BaseType
.
I've checked that this works with multiple different types for the second operand.
It's slightly annoying that you have to cast to Object
... I'm still working on alternatives for that...
Nullable type inference in Visual Basic – is it documented somewhere and can it be made more strict?
Okay, now I understand better. The culprit is in interpretation of Nothing
.
Change of Nothing
to “true” null
leads to correct result:
Dim i As Integer? = If(True, New Nullable(Of Integer), 3)
Result: i Is Nothing
so the possible problem was that Nothing
seems to be first viewed by compiler as default value for the other type (Integer) than a null
. Changing its implicit meaning helps. A tricky spot anyway. If someone can find this documented, it would be nice. (I do not insist on this answer.) It will be great if the VB can be forced to throw an error or warning when this happens, similar to C#.
As seen in comment elsewhere, a nicer form of notation can exist:
Dim i As Integer? = If(True, Integer?, 3)
Nice!
Is Nothing equal to Default?
If it's a value type (like Integer, Double, etc.) setting the variable to Nothing will set it to the default value.
If it's a reference type, it will really be set to Nothing (null value).
In Microsoft's words:
Assigning Nothing to a variable sets
it to the default value for its
declared type.If the variable is of a reference
type, a value of Nothing means that
the variable is not associated with
any object. The variable has a null
value.
Bug?? If you assign a value to a nullable integer via a ternary operator, it can't become null
The problem is that Nothing
in VB.NET works differently than, for example, null
in C#. When Nothing
is used in the context of a value type (such as Integer
) it represents the default value of that type. In this case, that's 0.
In your first example, both branches of the ternary operator are valid Integer
values. The true branch represents 0 and the false branch represents 43.
In the second example, neither branch of the ternary operator is a valid Integer
value, thus forcing the VB.NET compiler to assume that the overall operator returns Object
, not Integer
.
To make the first example work the way you intend, you need to make it clear to the compiler that the ternary operator should resolve to an Integer?
, not an Integer
or an Object
. You can do so like this:
dim val1 As Integer? = If(5 > 2, Nothing, New Integer?(43))
By explicitly making the false branch of the operator an Integer?
, the Nothing
in the true branch will represent the null value, instead of the default Integer
value.
Benefits of using the conditional ?: (ternary) operator
I would basically recommend using it only when the resulting statement is extremely short and represents a significant increase in conciseness over the if/else equivalent without sacrificing readability.
Good example:
int result = Check() ? 1 : 0;
Bad example:
int result = FirstCheck() ? 1 : SecondCheck() ? 1 : ThirdCheck() ? 1 : 0;
Conditional operator assignment with Nullablevalue types?
The problem occurs because the conditional operator doesn't look at how the value is used (assigned in this case) to determine the type of the expression -- just the true/false values. In this case, you have a null
and an Int32
, and the type can not be determined (there are real reasons it can't just assume Nullable<Int32>
).
If you really want to use it in this way, you must cast one of the values to Nullable<Int32>
yourself, so C# can resolve the type:
EmployeeNumber =
string.IsNullOrEmpty(employeeNumberTextBox.Text)
? (int?)null
: Convert.ToInt32(employeeNumberTextBox.Text),
or
EmployeeNumber =
string.IsNullOrEmpty(employeeNumberTextBox.Text)
? null
: (int?)Convert.ToInt32(employeeNumberTextBox.Text),
Related Topics
Removing Dynamically Created Controls in C#
Which Blocking Operations Cause an Sta Thread to Pump Com Messages
Reading from a Text File in C#
Does C# Support Project-Wide Default Namespace Imports Like Vb.Net
Manual Editing of *.Designer.Cs File
Entity Framework. Delete All Rows in Table
Finding All Combinations of Well-Formed Brackets
Change Connection String & Reload App.Config at Run Time
Cannot Find .Cs Files for Debugging .Net Source Code
C# Wait for User to Finish Typing in a Text Box
Is There a Reasonable Approach to "Default" Type Parameters in C# Generics
Using Tfs API, How to Find the Comments Which Were Made on a Code Review
Wait for a While Without Blocking Main Thread