views:

650

answers:

6

What (if any) is the difference between the results of the following two versions of this VB Linq query?

' assume we have an XElement containing employee details defined somewhere else

Dim ee = From e In someXML.<Employee> _
Select New With {.Surname = e.<Surname>, .Forename = e.<Forename>}

and

Dim ee = From e In someXML.<Employee> _
Select Surname = .Surname = e.<Surname>, .Forename = e.<Forename>

ie what is the point of the New ... With syntax?

I suspect that this has a simple answer, but I can't find it - any links to suitable tutorials or Microsoft documentation would be appreciated.

A: 

They're called Anonymous Types.

The main reason for their use is to keep the data from a query in a single object, so the iterators can continue to iterate over a list of objects.

They tend to work as temporary types for storage in the middle of a large or multi-part LINQ query.

Cameron MacFarland
Yes - I know what they are but what, if any, is the difference between these two forms of the syntax? The link you provided gives an example of both forms but does not say whether they are equivalent.
Steve Davies
Sure it does: I pointed out exactly where in that link for you.
Joel Coehoorn
ok - combining your link Cameron with Joel's explanation makes sense now. Thank you all very much.
Steve Davies
A: 

The difference is that the 1st explicitly creates an anonymous type. The 2nd is a query expression, and may use an existing type rather than creating an anonymous type. From the documentation linked by Cameron MacFarland:

Query expressions do not always require the creation of anonymous types. When possible, they use an existing type to hold the column data. This occurs when the query returns either whole records from the data source, or only one field from each record.

Joel Coehoorn
Does not it just mean that when you are selecting a _single_ column there is no anonymous type? So it is not applicable to the example above, where 2 columns are used.
Andrey Shchekin
Yes, there's probably no difference in that example. But in the _general_ case, that is the _potential_ difference. Also, it can use an existing type if you bring back the entire record, so it's not just for single columns.
Joel Coehoorn
Both peices of code use an anonymous type, always.
JaredPar
Is the documentation wrong, then, or are you referring only to the specific code snippet in the question rather than the general case?
Joel Coehoorn
Key phrase in your quote is "whole records from the data source, or only one field from each record." If the query only returned one element.Value, then the result would be IQueryable(Of String). When there are multiple values returned, then it will be an anonymous type or some explicitly named type as I show in my answer.
Dennis Palmer
A: 

My understanding is that there is no difference.

New With is aimed to out-of-query usage like

Dim X = New With { .Surname = "A", .Forename = "B" }

Specifically for Linq queries, you can skip New With, but it is still useful for other situations. I am not sure, however, since I do not know VB 9 :)

Andrey Shchekin
A: 

One difference is that Anonymous types aren't serializable.

Shawn Simon
+1  A: 

There is no functional difference between the two pieces of code you listed. Under the hood both pieces code will use an anonymous type to return the data from the query.

The first piece of code merely makes the use of an anonymous type explicit. The reason this syntax is allowed is that it's possible to return any type from a Select clause. But the type must be used explicitly.

Dim x = From it in SomeCollection Select New Student With { .Name = it.Name }

Joel is incorrect in his statement that the second query may use an existing type. Without an explicit type, a select clause which uses an explicit property name will always return an anonymous type.

JaredPar
A: 

There is no difference. The compiler will infer the anonymous type.

You most likely want to return the Value of the elements as in e.<Surname>.Value, which returns a String instead of an XElement.

Your 2nd example could be simplified as

Dim ee = From e In someXML.<Employee> _
         Select e.<Surname>.Value, e.<Forename>.Value

because the compiler will also infer the names of the members of the anonymous type.

However, if you have the following class

Class Employee

    Private _surname As String
    Public Property Surname() As String
        Get
            Return _surname
        End Get
        Set(ByVal value As String)
            _surname = value
        End Set
    End Property

    Private _forename As String
    Public Property Forename() As String
        Get
            Return _forename
        End Get
        Set(ByVal value As String)
            _forename = value
        End Set
    End Property

End Class

Then you could change the 1st query to produce an IQueryable(Of Employee) instead of the anonymous type by using New ... With like so:

Dim ee = From e In someXML.<Employee> _
         Select New Employee With {.Surname = e.<Surname>.Value, _
                                   .Forename = e.<Forename>.Value}
Dennis Palmer