tags:

views:

101

answers:

2

I would expect the following vb.net function to return a value of Nothing, but instead its returning a value of 0...

Public Shared Function GetDefaultTipoSrvTkt() As Integer?
    Dim tsrvDict As New Dictionary(Of Integer, DataRow) 
    GetDefaultTipoSrvTkt = If(IsNothing(tsrvDict) OrElse tsrvDict.Count = 0, Nothing, tsrvDict.First.Key)
End Function

The last line of the function could also be written as Return If(IsNothing(tsrvDict) OrElse tsrvDict.Count = 0, Nothing, tsrvDict.First.Key) but in any case, why is the IF() function If(IsNothing(tsrvDict) OrElse tsrvDict.Count = 0, Nothing, tsrvDict.First.Key) returning 0 instead of Nothing?

+3  A: 

Nothing in VB can be applied to value types as well as reference types, and in all cases means "default value of this type". So, for example:

Dim x As Integer = Nothing
Console.WriteLine(x) ' 0

For If() operator, VB has to deduce the return type somehow. It looks at both branches, and figures out the nearest common type for them. In this case, one branch is of type Integer. Another is Nothing, which is "typeless", but it is compatible with Integer, as we saw earlier. Therefore, the result type of If() is deduced to be Integer. When Nothing is returned in that context, it becomes 0.

An explicit cast will fix this:

GetDefaultTipoSrvTkt = If( _
    IsNothing(tsrvDict) OrElse tsrvDict.Count = 0, _
    CType(Nothing, Integer?), _
    tsrvDict.First.Key)

or you can use an alternative way to specify the null value for a nullable type:

GetDefaultTipoSrvTkt = If( _
    IsNothing(tsrvDict) OrElse tsrvDict.Count = 0, _
    New Integer?(), _ 
    tsrvDict.First.Key)
Pavel Minaev
Good answer. If you want your function to return Nothing instead of 0, just convert the second argument to a nullable integer.
Meta-Knight
Indeed, I solved the problem by changing the variable declaration statement to:Dim tsrvDict As New Dictionary(Of Integer?, DataRow)Great answer, I am always intrigued as to how so many years of programming matter so little when faced with unknown details, or as in this case for me, unforeseen, yet logical, results.Id love more the new IF() operator if it had the option of being declared with a generics method, as in If(Of TReturn)(...) so that you could force it a return type instead of it having to determine it based on its branches...
Rodolfo G.
Well, it's not fundamentally different from using `CType` on one of the branches.
Pavel Minaev
A: 

I think Rodolfo has simplified the real code to make a short question, which is of course a good idea. But it is a little odd.

  • Dim x As New Y is equivalent to Dim x As Y: x = New Y, so a new dictionary is created every time the statement is executed. So the function always returns Nothing, and the dictionary never gets any entries, and goes out of scope immediately when the function returns.

Pavel's answer is probably the most helpful. But it is complex enough that I would just write a normal If statement

If tsrvDict Is Nothing OrElse tsrvDict.Count = 0 Then  
  Return Nothing  
Else   
  Return tsrvDict.First.Key   
End If
MarkJ
No, `If()` doesn't evaluate both of its argument. You've actually got it the wrong way - the legacy `IIf()` function inherited from VB6 evaluates all arguments (because, well, it's a function), while `If()` is an operator, and short-circuits the same way `?:` does in C#.
Pavel Minaev
Yes, I realised that just after I submitted my answer. You comment very fast, kudos for that.
MarkJ