I am researching how LINQ expressions get compiled into code...more specifically the function chaining that gets generated. (The background reason for this is I wanted to more thoroughly understand the objects that get created during joins. I need to code for a COALESCE in the SELECT for two properties from the different tables.)
I tend to prefer the dot notation when building my LINQ expressions but most tutorials and samples use the expression syntax so I wrote a sample app and used reflector to see what the resulting code looked like.
As expected, the following code compiled into the same exact code. (The important piece are the last two lines.)
Dim invoicesStore = New List(Of Invoice)()
invoicesStore.Add(New Invoice() With {.Id = 1, .DueDate = #2/1/2010#})
invoicesStore.Add(New Invoice() With {.Id = 2, .DueDate = #3/21/2010#})
...
Dim detailsStore = New List(Of InvoiceDetail)()
detailsStore.Add(New InvoiceDetail() With {.DetailId = 1, .InvoiceId = 1, .Amount = 10.23D})
detailsStore.Add(New InvoiceDetail() With {.DetailId = 2, .InvoiceId = 2, .Amount = 23.24D})
...
Dim invoices1 = From i In invoicesStore Join d In detailsStore On d.InvoiceId Equals i.Id
Dim invoices2 = invoicesStore.Join(detailsStore, Function(i) i.Id, Function(d) d.InvoiceId, Function(i, d) New With {i, d})
generated
Dim invoicesStore As New List(Of Invoice) { New Invoice { _
.Id = 1, _
.DueDate = New DateTime(&H8CC70E8A1B34000) _
}, New Invoice { _
.Id = 2, _
.DueDate = New DateTime(&H8CC96A095874000) _
}, New Invoice { _
...
Dim detailsStore As New List(Of InvoiceDetail) { New InvoiceDetail { _
.DetailId = 1, _
.InvoiceId = 1, _
.Amount = 10.23 _
}, New InvoiceDetail { _
.DetailId = 2, _
.InvoiceId = 2, _
...
Dim invoices1 As IEnumerable(Of VB$AnonymousType_0(Of Invoice, InvoiceDetail)) = invoicesStore.Join(Of Invoice, InvoiceDetail, Integer, VB$AnonymousType_0(Of Invoice, InvoiceDetail))(detailsStore, New Func(Of Invoice, Integer)(AddressOf Module1._Lambda$__1), New Func(Of InvoiceDetail, Integer)(AddressOf Module1._Lambda$__2), New Func(Of Invoice, InvoiceDetail, VB$AnonymousType_0(Of Invoice, InvoiceDetail))(AddressOf Module1._Lambda$__3))
Dim invoices2 As IEnumerable(Of VB$AnonymousType_1(Of Invoice, InvoiceDetail)) = invoicesStore.Join(Of Invoice, InvoiceDetail, Integer, VB$AnonymousType_1(Of Invoice, InvoiceDetail))(detailsStore, New Func(Of Invoice, Integer)(AddressOf Module1._Lambda$__4), New Func(Of InvoiceDetail, Integer)(AddressOf Module1._Lambda$__5), New Func(Of Invoice, InvoiceDetail, VB$AnonymousType_1(Of Invoice, InvoiceDetail))(AddressOf Module1._Lambda$__6))
However, the following code (I only included the relevant lines)
Dim invoices1 = From i In invoicesStore Join d In detailsStore On d.InvoiceId Equals i.Id Select i
Dim invoices2 = invoicesStore.Join(detailsStore, Function(i) i.Id, Function(d) d.InvoiceId, Function(i, d) New With {i, d}).Select(Function(o) o.i)
generated
Dim invoices1 As IEnumerable(Of Invoice) = invoicesStore.Join(Of Invoice, InvoiceDetail, Integer, Invoice)(detailsStore, New Func(Of Invoice, Integer)(AddressOf Module1._Lambda$__1), New Func(Of InvoiceDetail, Integer)(AddressOf Module1._Lambda$__2), New Func(Of Invoice, InvoiceDetail, Invoice)(AddressOf Module1._Lambda$__3))
Dim invoices2 As IEnumerable(Of Invoice) = invoicesStore.Join(Of Invoice, InvoiceDetail, Integer, VB$AnonymousType_0(Of Invoice, InvoiceDetail))(detailsStore, New Func(Of Invoice, Integer)(AddressOf Module1._Lambda$__4), New Func(Of InvoiceDetail, Integer)(AddressOf Module1._Lambda$__5), New Func(Of Invoice, InvoiceDetail, VB$AnonymousType_0(Of Invoice, InvoiceDetail))(AddressOf Module1._Lambda$__6)).Select(Of VB$AnonymousType_0(Of Invoice, InvoiceDetail), Invoice)(New Func(Of VB$AnonymousType_0(Of Invoice, InvoiceDetail), Invoice)(AddressOf Module1._Lambda$__7))
While the end result and data types are the same I was wondering why the different code. I can probably guess that it is compiler optimizations but the sample is somewhat simple and cannot help wonder if there is an actual difference in the code.
Thanks.