Implicit Conversion: Nullable(Of T) => T | VB.NET LINQ Query Syntax Vs Method Syntax

262 views Asked by At

The method syntax is blocking implicit conversions, but the query syntax is not. Option Strict is on. How can I force errors to appear when using the query syntax?

Whole (Completely Runnable) Program:

Option Strict On

Module Module1

Sub Main()

    Dim custList As New List(Of Cust)()
    custList.Add(New Cust() With {.Name = "Mr. Current", .Deleted = False})
    custList.Add(New Cust() With {.Name = "Mrs. Deleted", .Deleted = True})
    custList.Add(New Cust() With {.Name = "Miss Null", .Deleted = Nothing})

    Dim QuerySyntax =
        From c In custList
        Where c.Deleted = False 'no error (the problem)

    Dim MethodSyntax =
        custList _
        .Where(Function(c) c.Deleted = False) 'compiler error (desired effect)

    For Each c As Cust In QuerySyntax
        Console.WriteLine("Q: " & c.Name & " " & c.Deleted)
    Next

    For Each c As Cust In MethodSyntax
        Console.WriteLine("M: " & c.Name & " " & c.Deleted)
    Next

    Console.ReadKey(True)

End Sub

Class Cust
    Public Property Name() As String
    Public Property Deleted() As System.Nullable(Of Boolean)
End Class

End Module

Lines that are the crux of the question:

Where c.Deleted = False 'no error
.Where(Function(c) c.Deleted = False) 'compiler error
2

There are 2 answers

2
David W On

I'm going to go out at least a bit of a limb and offer that I've found an explanation for this behavior.

I took this code and changed 'c.Deleted = Nothing' in the QuerySyntax version and immediately got a "green squiggly" saying "This expression will always evaluate to Nothing due to null propagation of the equals operator." That led me to think about how the compiler is interpreting the expression, and so I did a bit more snooping, and found the following:

VB.Net Linq to Entities Null Comparison - 'Is Nothing' or '= Nothing'?

From that post, it appears that when a Nullable(Of T) is involved in the expression, the compiler is internally promoting (or, I suppose, more accurately, "lifting") the equality operator to Nullable(Of T) version, which I suppose is not, technically, an "implicit conversion." As a result, it doesn't generate the compile-time error. Because the element is passed as a parameter to the function in the MethodSyntax version, the lifting operator isn't being applied, and the compiler then traps the implicit conversion syntax.

0
Vincent Saelzler On

Thanks @David W for the comments, they helped a lot in pointing me to the answer!

Method Syntax:

The .Where method is specifically the System.Linq.Enumerable.Where method, and it specifies that the predicate parameter is a labmba function that returns a Boolean value. As @GSerg ponted out, the comparison will return a Boolean? value, hence the compiler throws an error.

MSDN: Extension Method

Query Syntax

In contrast, the Where clause of the query syntax accepts "an expression" as the condition parameter.

Regarding this condition paramater, MSDN goes on to say:

The expression that is used in a Where clause must evaluate to a Boolean or the equivalent of a Boolean, such as an Integer that evaluates to False when its value is zero.

MSDN: Where Clause

Conclusion

In other words, using the query syntax, the expression will always be evaluated. As a result, Option Strict will have no effect because the compiler is considering the result of the evaluated expression and not the data types of the expression itself.