Teejay
Teejay

Reputation: 7479

Mystery of the If() function in VB.net

I have this code:

dstCell.CELL_VALUE_INT = If(srcCell.CELL_VALUE_FLOAT IsNot Nothing,
                            Math.Round(CDbl(srcCell.CELL_VALUE_FLOAT)),
                            Nothing)

when srcCell.CELL_VALUE_FLOAT is Nothing it mysteriously evaluates to the True part!

Funny part is that a normal If statement correctly evaluates to the False part:

If (srcCell.CELL_VALUE_FLOAT IsNot Nothing) Then
    dstCell.CELL_VALUE_INT = Math.Round(CDbl(srcCell.CELL_VALUE_FLOAT))
Else
    dstCell.CELL_VALUE_INT = Nothing
End If

Any ideas?

Thank u!

EDIT: CELL_VALUE_FLOAT is a Nullable(Of Double) and CELL_VALUE_INT is a Nullable(of Integer)

In Quickwatch the condition evaluates correclty to False, but when running the If() function evaluates to the True part.

Upvotes: 6

Views: 7264

Answers (3)

Jürgen Steinblock
Jürgen Steinblock

Reputation: 31733

Nothing in VB.NET is not fully equal to null in C# It is more like default(T) where T is a Type.

' VB:
dim x as DateTime = DateTime.MinValue
If x Is Nothing then
    Console.WriteLine("True")
End if

' C#
var x = DateTime.MinValue
if (x == default(DateTime))
    Console.WriteLine("True");

if (x == null) ' throw a compile time error

And

dim x as Double = nothing ' x will be 0 (default for Double)

the build in inline if expects both return values to be the same type. So what you a really doing is:

dstCell.CELL_VALUE_INT = If(srcCell.CELL_VALUE_FLOAT IsNot Nothing,
                            Math.Round(CDbl(srcCell.CELL_VALUE_FLOAT)),
                            Convert.ToDouble(Nothing))

since the false part gets internally converted to double and dstCell.CELL_VALUE_INT will be 0 instead of nothing.

Try this one:

dstCell.CELL_VALUE_INT = If(srcCell.CELL_VALUE_FLOAT IsNot Nothing,
                         Ctype(Math.Round(CDbl(srcCell.CELL_VALUE_FLOAT)), Integer?),
                         Nothing)

Upvotes: 4

Heinzi
Heinzi

Reputation: 172280

when srcCell.CELL_VALUE_FLOAT is Nothing it mysteriously evaluates to the True part!

Nope, it does not. It just evalues the false part (Nothing) as 0, thus setting CELL_VALUE_INT to 0.


Let me elaborate: The expression

Dim i As Integer? = If(False, 1, Nothing)

fills i with 0. (Test it, if you don't believe me.)

Why does this happen? Nothing in VB.NET is not the same as null in C#. If used with a value type, Nothing means "the default value of that type". If infers Integer (not Integer?) as the common type for 1 and Nothing, and, thus, evaluates Nothing as default(Integer) = 0.

You can fix this as follows:

Dim i As Integer? = If(False, 1, DirectCast(Nothing, Integer?))

which, in your example, would mean

dstCell.CELL_VALUE_INT = If(srcCell.CELL_VALUE_FLOAT IsNot Nothing,   
                            Math.Round(CDbl(srcCell.CELL_VALUE_FLOAT)),   
                            DirectCast(Nothing, Integer?))  

This should yield the correct value now.


Since this is quite surprising behaviour, I have filed a Microsoft Connect suggestion some time ago to add a compiler warning.

Upvotes: 10

Tim Schmelter
Tim Schmelter

Reputation: 460158

Assuming that your value is a Single(Float):

The default value of Single is 0 not Nothing.

You can use a Nullable(Of T) if you want to check for null values.

Dim srcCell.CELL_VALUE_FLOAT As Nullable(Of Single)
srcCell_CELL.VALUE_FLOAT = Nothing
Dim dstCell.CELL_VALUE_INT As Nullable(Of Int32) = _
    (If(srcCell.CELL_VALUE_FLOAT.HasValue,
        CInt(Math.Round(CDbl(srcCell.CELL_VALUE_FLOAT))),
        Nothing))

Upvotes: 0

Related Questions