A staple of .NET programming is the use of LINQ to simplify a lot of common operations.

LINQ also offers the ability to join data, and perform a variety of operations.

Take, for example, the following type for a Product:

public class Product
{
  public required int ID { get; init; }
  public required string Name { get; init; }
}

Let us add another type, an Order:

public class Order
{
  public required int OrderID { get; init; }
  public required int ProductID { get; init; }
  public required int Quantity { get; init; }
}

We then create a collection of Product:

Product[] products = [
  new Product { ID = 1, Name = "Mango" },
  new Product { ID = 2, Name = "Banana" },
  new Product { ID = 3, Name = "Potato" },
  new Product { ID = 4, Name = "Cabbage" },
];

And another collection of Order:

Order[] orders =
[
  new Order{ OrderID=1, ProductID=1,Quantity=10 },
  new Order{ OrderID=1, ProductID=2,Quantity=13 },
  new Order{ OrderID=2, ProductID=3,Quantity=5 },
  new Order{ OrderID=2, ProductID=4,Quantity=8 },
];

Suppose we wanted to iterate over all the orders and print the Product name and quantity. We can achieve this using a LINQ JOIN, like this:

var result = products.Join(orders,
		product => product.ProductID,
		order => order.ProductID,
		(product, order) => (product, order));

This would project the result of each join operation into a tuple that we can iterate over, like this:

foreach (var (product, order) in result)
{
  Console.WriteLine($"Product: {product.Name}, Quantity: {order.Quantity}");
}

This will print the following:

Product: Mango, Quantity: 10
Product: Banana, Quantity: 13
Product: Potato, Quantity: 5
Product: Cabbage, Quantity: 8

linqResults

Note that there is some ceremony, including generation of an intermediate resultset of tuples:

var result = products.Join(orders,
		product => product.ProductID,
		order => order.ProductID,
		(product, order) => (product, order));

This has been simplified in .NET 11.

We can get the exact same result like this:

var newResult = products.Join(orders,
		product => product.ProductID,
		order => order.ProductID);

Note here we do not need to construct our tuple in advance, and that the generated data structure being returned is identical in both cases:

projection

TLDR

Projection of LINQ JOIN results is simplified in .NET 11

The code is in my GitHub.

Happy hacking!