18

I'm normally at home in C#, and I'm looking at a performance issue in some VB.NET code -- I want to be able to compare something to the default value for a type (kind of like C#'s default keyword).

public class GenericThing<T1, T2>
{
    public T1 Foo( T2 id )
    {
        if( id != default(T2) ) // There doesn't appear to be an equivalent in VB.NET for this(?)
        {
            // ...
        }
    }
}

I was led to believe that Nothing was semantically the same, yet if I do:

Public Class GenericThing(Of T1, T2)
    Public Function Foo( id As T2 ) As T1
        If id IsNot Nothing Then
            ' ...
        End If
    End Function
End Class

Then when T2 is Integer, and the value of id is 0, the condition still passes, and the body of the if is evaluated. However if I do:

    Public Function Bar( id As Integer ) As T1
        If id <> Nothing Then
            ' ...
        End If
    End Function

Then the condition is not met, and the body is not evaluated...

Rowland Shaw
  • 37,700
  • 14
  • 97
  • 166

3 Answers3

22

Unlike C#, VB.NET doesn't require a local variable to be initialized with an expression. It gets initialized to its default value by the runtime. Just what you need as a substitute for the default keyword:

    Dim def As T2    '' Get the default value for T2
    If id.Equals(def) Then
       '' etc...
    End If

Don't forget the comment, it is going to make somebody go 'Huh?' a year from now.

Hans Passant
  • 922,412
  • 146
  • 1,693
  • 2,536
12

This is not a complete solution, as your original C# code doesn't compile. You can use Nothing via a local variable:

Public Class GenericThing(Of T)
    Public Sub Foo(id As T)
        Dim defaultValue As T = Nothing
        If id <> defaultValue Then
            Console.WriteLine("Not default")
        Else
            Console.WriteLine("Default")
        End If
    End Function
End Class

That doesn't compile, in the same way that the C# version doesn't compile - you can't compare values of unconstrained type parameters like that.

You can use EqualityComparer(Of T) though - and then you don't even need the local variable:

If Not EqualityComparer(Of T).Default.Equals(id, Nothing) Then
Jon Skeet
  • 1,421,763
  • 867
  • 9,128
  • 9,194
  • I think I took a bit too much business specific terms out of my examples, but that *seems* to work for value types - do you know how well it would work for reference types as well? – Rowland Shaw Jan 20 '11 at 17:26
  • @Rowland: It should be fine as far as I'm aware. – Jon Skeet Jan 20 '11 at 17:27
  • Well, it's compiling as I type, so I'll soon know for sure; I can see how that would force the compiler to do magic and get it to work – Rowland Shaw Jan 20 '11 at 17:29
5

The problem in your code is the IsNot operator, not the Nothing keyword. From the docs:

The IsNot operator determines if two object references refer to different objects. However, it does not perform value comparisons.

You're trying to do a value comparison with a reference operator. Once you realize this, either Jon Skeet's or Hans Passant's answers become obvious solutions.

Joel Coehoorn
  • 399,467
  • 113
  • 570
  • 794
  • Makes perfect sense - it's always annoys me that VB has both `=` and `Is` for comparisons, with it being up to the developer to know whether to compare value or reference types, respectively. – Rowland Shaw Jan 20 '11 at 18:46
  • @Rowland - C# has an "is" operator also. I use this rule of thumb that works for both C# and VB: use .Equals() first, if the compiler complains use == / =, and if the compiler still complains use is. – Joel Coehoorn Jan 20 '11 at 21:33
  • @Joel/Rowland, habit has me favoring =/== with object/classes.. I tend to use Equals when using nullable types (Guid?,DateTime?, etc). I come across a lot of code that treats Guids improperly (as strings) instead of Guid? ... it actually irks me more in SQL when I have to use is null, where = null will usually bork what I am trying to do. – Tracker1 Sep 22 '11 at 18:37