201

Is there a VB.NET equivalent for C#'s ?? operator?

Stephen Kennedy
  • 20,585
  • 22
  • 95
  • 108
Nathan Koop
  • 24,803
  • 25
  • 90
  • 125
  • 4
    Most of the answers here (including the accepted answer) are not correct, and are not functionally equivalent to ?? in all situations. The correct equivalent is the if() statement with 2 arguments. The second argument however can be nested to achieve exactly the same results as ?? with multiple arguments. – user1751825 May 21 '17 at 04:26
  • Do you mean the ternary operator ?: e.g. return ((value < 0)?true:false) – Zeek2 Oct 24 '19 at 15:23

6 Answers6

175

Use the If() operator with two arguments (Microsoft documentation):

' Variable first is a nullable type.
Dim first? As Integer = 3
Dim second As Integer = 6

' Variable first <> Nothing, so its value, 3, is returned.
Console.WriteLine(If(first, second))

second = Nothing
' Variable first <> Nothing, so the value of first is returned again. 
Console.WriteLine(If(first, second))

first = Nothing second = 6
' Variable first = Nothing, so 6 is returned.
Console.WriteLine(If(first, second))
djv
  • 15,168
  • 7
  • 48
  • 72
Firas Assaad
  • 25,006
  • 16
  • 61
  • 78
  • IF is the coalesce operator in VB – Nick Dec 31 '08 at 16:53
  • 5
    I think the `If()` statement in VB is the same as the `if...?...:` in C#, not the `??` operator – Luke T O'Brien Dec 16 '16 at 10:50
  • 3
    @LukeTO'Brien That's if you use it with 3 arguments. If you use it with 2 arguments, it is more that `??` (see another answer to this question: http://stackoverflow.com/a/20686360/1474939) – Brian J Dec 21 '16 at 14:10
  • 2
    This answer shows how to use VB `If` *with three parameters*. That is **not** similar to C#'s `??` operator. Better answer is [Code Maverick's If with two arguments](http://stackoverflow.com/a/20686360/199364). (Nick had a similar answer, years earlier, but doesn't include the explanation from MSDN.) – ToolmakerSteve May 20 '17 at 16:26
  • Used in this manner, with 3 arguments, the If() statement is not equivalent to ??. To be truly equivalent, you can only use it with 2 parameters. It can however be nested, see my answer bellow. – user1751825 May 21 '17 at 04:13
  • 1
    This answers a completely different question. – Marc Gravell Mar 09 '18 at 23:48
  • 5
    To understand the previous comments, look at the edit history. – Zev Spitz Jul 11 '18 at 07:20
110

The IF() operator should do the trick for you:

value = If(nullable, defaultValueIfNull)

http://visualstudiomagazine.com/listings/list.aspx?id=252

Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
Nick
  • 9,113
  • 4
  • 25
  • 29
75

The accepted answer doesn't have any explanation whatsoever and is simply just a link.
Therefore, I thought I'd leave an answer that explains how the If operator works taken from MSDN:


If Operator (Visual Basic)

Uses short-circuit evaluation to conditionally return one of two values. The If operator can be called with three arguments or with two arguments.

If( [argument1,] argument2, argument3 )


If Operator Called with Two Arguments

The first argument to If can be omitted. This enables the operator to be called by using only two arguments. The following list applies only when the If operator is called with two arguments.


Parts

Term         Definition
----         ----------

argument2    Required. Object. Must be a reference or nullable type. 
             Evaluated and returned when it evaluates to anything 
             other than Nothing.

argument3    Required. Object.
             Evaluated and returned if argument2 evaluates to Nothing.


When the Boolean argument is omitted, the first argument must be a reference or nullable type. If the first argument evaluates to Nothing, the value of the second argument is returned. In all other cases, the value of the first argument is returned. The following example illustrates how this evaluation works.


VB

' Variable first is a nullable type. 
Dim first? As Integer = 3
Dim second As Integer = 6

' Variable first <> Nothing, so its value, 3, is returned.
Console.WriteLine(If(first, second))

second = Nothing 
' Variable first <> Nothing, so the value of first is returned again.
Console.WriteLine(If(first, second))

first = Nothing
second = 6
' Variable first = Nothing, so 6 is returned.
Console.WriteLine(If(first, second))

An example of how to handle more than two values (nested ifs):

Dim first? As Integer = Nothing
Dim second? As Integer = Nothing
Dim third? As Integer = 6
' The LAST parameter doesn't have to be nullable.
'Alternative: Dim third As Integer = 6

' Writes "6", because the first two values are "Nothing".
Console.WriteLine(If(first, If(second, third)))
ToolmakerSteve
  • 18,547
  • 14
  • 94
  • 196
Code Maverick
  • 20,171
  • 12
  • 62
  • 114
20

You can use an extension method. This one works like SQL COALESCE and is probably overkill for what you are trying to test, but it works.

    ''' <summary>
    ''' Returns the first non-null T based on a collection of the root object and the args.
    ''' </summary>
    ''' <param name="obj"></param>
    ''' <param name="args"></param>
    ''' <returns></returns>
    ''' <remarks>Usage
    ''' Dim val as String = "MyVal"
    ''' Dim result as String = val.Coalesce(String.Empty)
    ''' *** returns "MyVal"
    '''
    ''' val = Nothing
    ''' result = val.Coalesce(String.Empty, "MyVal", "YourVal")
    ''' *** returns String.Empty
    '''
    ''' </remarks>
    <System.Runtime.CompilerServices.Extension()> _
    Public Function Coalesce(Of T)(ByVal obj As T, ByVal ParamArray args() As T) As T

        If obj IsNot Nothing Then
            Return obj
        End If

        Dim arg As T
        For Each arg In args
            If arg IsNot Nothing Then
                Return arg
            End If
        Next

        Return Nothing

    End Function

The built-in If(nullable, secondChoice) can only handle two nullable choices. Here, one can Coalesce as many parameters as desired. The first non-null one will be returned, and the rest of the parameters are not evaluated after that (short circuited, like AndAlso/&& and OrElse/|| )

StingyJack
  • 19,041
  • 10
  • 63
  • 122
  • 9
    Because the language has a built in operator. No reason to even look at extension methods. – Nick Dec 31 '08 at 16:59
  • 3
    I'm not going to repeat someone else's answer. I figured that it may be nice to provide an alternate solution if you need to check multiple values with a single statement. Since its not a WRONG answer, then should it be downvoted? – StingyJack Dec 31 '08 at 17:08
  • 1
    +1 for providing an implementation using generics and avoiding type casting/boxing/unboxing – ulty4life Dec 10 '13 at 22:54
  • 4
    @Nick, sorry, but you are just plain wrong. If you have more than two coalesce arguments, the built in function won't cut it. – toddmo Oct 13 '14 at 17:19
  • 1
    You could skip the obj param and let the body be `Return args.FirstOrDefault(Function(arg) arg IsNot Nothing)` :-) – Ulf Åkerstedt Sep 03 '15 at 13:51
  • @Nick, i quite disagree. I think extension methods are VERY convenient and useful to handle nulls. the If() is very verbose while extension methods yield code that is much more readable than a bunch of sloppy If()'s in code. – Shawn Kovac Aug 02 '16 at 12:45
  • I give a simple example of using extension methods over If(). Let the reader judge which is cleaner: extension method: `myString.ToLowerCase()` or Nick's preferred If() method: `if(myString is nothing, nothing, myString.ToLowerCase())`. This is why i quite disagree with your comment, Nick, that there's no reason to look at extension methods. Altho in this case, the new ?. operator is much preferred, but sometimes we don't have the option of using VB 14 yet, so extension methods are still the next best thing over the If() method. Well, according to my humble opinion. But that's only my opinion. – Shawn Kovac Aug 02 '16 at 12:54
  • (in the above code, i propose that a programmer discard `Dim arg As T` and use `For Each arg as T In args` instead of the current `For Each` line. Just one less line of code.) – Shawn Kovac Aug 02 '16 at 12:57
  • @ShawnKovac- feel free to make these kind of edits. Improvements to existing and other useful answers are welcome. – StingyJack Aug 02 '16 at 21:29
  • I like this solution, because it is capable of handling more than three alternatives. HOWEVER, I dislike the extension method representation. I dislike it because it makes `obj` and the other parameters "look different" in the call site. `val1.Coelesce(val2, val3)` doesn't feel right to me. I would *remove* the `CompilerServices.Extension` and `obj as T`, so that usage would be `Coealesce(val1, val2, val3)`, Per Ulf's comment, implementation becomes one-line `Return args.FirstOrDefault(Function(arg) arg IsNot Nothing)`. – ToolmakerSteve May 20 '17 at 16:43
  • @ToolmakerSteve - I dislike that VB still requires the system.compilerservices.extension attribute, but that's what it needs to work in VB. If you don't mind adding the non-extension method variants to your own answer it would be appreciated, as this one now sounds quite a bit schizophrenic. – StingyJack May 21 '17 at 02:37
13

The one significant limitation of most of these solutions is that they won't short-circuit. They are therefore not actually equivalent to ??.

The built-in If operator won't evaluate subsequent parameters unless the earlier parameter evaluates to nothing.

The following statements are equivalent:

C#

var value = expression1 ?? expression2 ?? expression3 ?? expression4;

VB

dim value = if(expression1,if(expression2,if(expression3,expression4)))

This will work in all cases where ?? works. Any of the other solutions would have to be used with extreme caution, as they could easily introduce run-time bugs.

Andrew Morton
  • 24,203
  • 9
  • 60
  • 84
user1751825
  • 4,029
  • 1
  • 28
  • 58
  • This does not work in cases where there are an unknown number of parameters (well.. not without using roslyn or codedom to precompile a statement to match the number of parameters at that moment in the execution). – StingyJack May 21 '17 at 02:41
  • @StingyJack It's not intended to. It does exactly what the ?? operator does. – user1751825 May 21 '17 at 04:10
3

Check Microsoft documentation about If Operator (Visual Basic) here: https://learn.microsoft.com/en-us/dotnet/visual-basic/language-reference/operators/if-operator

If( [argument1,] argument2, argument3 )

Here are some examples (VB.Net)

' This statement prints TruePart, because the first argument is true.
Console.WriteLine(If(True, "TruePart", "FalsePart"))

' This statement prints FalsePart, because the first argument is false.
Console.WriteLine(If(False, "TruePart", "FalsePart"))

Dim number = 3
' With number set to 3, this statement prints Positive.
Console.WriteLine(If(number >= 0, "Positive", "Negative"))

number = -1
' With number set to -1, this statement prints Negative.
Console.WriteLine(If(number >= 0, "Positive", "Negative"))
FN90
  • 421
  • 4
  • 13