LINQ

27.1 Query Syntax (VB Style)

Dim products = New List(Of Product) From {
    New Product With {.Name = "Laptop", .Category = "Tech", .Price = 1200D, .Stock = 5},
    New Product With {.Name = "Phone", .Category = "Tech", .Price = 800D, .Stock = 0},
    New Product With {.Name = "Desk", .Category = "Furniture", .Price = 300D, .Stock = 12},
    New Product With {.Name = "Chair", .Category = "Furniture", .Price = 150D, .Stock = 20}
}

Dim expensive = From p In products
                Where p.Price > 200 AndAlso p.Stock > 0
                Order By p.Price Descending
                Select p.Name, p.Price                 ' anonymous type with Name and Price

For Each item In expensive
    Console.WriteLine($"{item.Name}: {item.Price:C}")
Next

Dim byCategory = From p In products
                 Group By p.Category Into Count(), Total = Sum(p.Price), Items = Group
                 Order By Total Descending

For Each g In byCategory
    Console.WriteLine($"{g.Category}: {g.Count} items, {g.Total:C}")
Next

Dim totalStock = Aggregate p In products Into Sum(p.Stock)           ' VB-only Aggregate clause
Dim stats = Aggregate p In products Into Min(p.Price), Max(p.Price), Average(p.Price)
Console.WriteLine($"{stats.Min
…

27.2 Joins

Dim orders = {New With {.OrderId = 1, .ProductName = "Laptop", .Qty = 2},
              New With {.OrderId = 2, .ProductName = "Desk", .Qty = 1}}

Dim joined = From o In orders
             Join p In products On o.ProductName Equals p.Name
             Select o.OrderId, p.Name, LineTotal = o.Qty * p.Price

Dim groupJoined = From p In products
                  Group Join o In orders On p.Name Equals o.ProductName Into ProductOrders = Group
                  Select p.Name, OrderCount = ProductOrders.Count()

Dim leftJoin = From p In products
               Group Join o In orders On p.Name Equals o.ProductName Into g = Group
               From o In g.DefaultIfEmpty()
               Select p.Name, Qty = If(o Is Nothing, 0, o.Qty)

27.3 Method Syntax

Dim names = products.Where(Function(p) p.Stock > 0).
                     OrderBy(Function(p) p.Name).
                     Select(Function(p) p.Name.ToUpper()).
                     ToList()

Dim total = products.Sum(Function(p) p.Price * p.Stock)
Dim cheapest = products.MinBy(Function(p) p.Price)              ' .NET 6+
Dim anyOut = products.Any(Function(p) p.Stock = 0)
Dim allPositive = products.All(Function(p) p.Price > 0)
Dim first = products.FirstOrDefault(Function(p) p.Category = "Toys")   ' Nothing if not found
Dim lookup = products.ToDictionary(Function(p) p.Name)
Dim grouped = products.GroupBy(Function(p) p.Category).
                       Select(Function(g) New With {.Cat = g.Key, .Count = g.Count()})
Dim chunks = Enumerable.Range(1, 10).Chunk(3)                   ' .NET 6+
Dim flat = {New Integer() {1, 2}, New Integer() {3}}.SelectMany(Function(a) a)
Dim zipped = {1, 2, 3}.Zip({"a", "b", "c"}, Function(n, s) $"{n}{s}")

27.4 Deferred vs Immediate Execution

Queries run when they're enumerated (deferred). Call .ToList(), .ToArray(), .Count(), or .First() to execute immediately.

LINQ to Objects works on in-memory data, LINQ to XML on XDocument, LINQ to Entities (EF Core) is translated to SQL, and PLINQ (.AsParallel()) runs in parallel.