Most likely FirstOrDefault can not be translated. Although the following uses records conceptually this is how to write the code. Records are easier to write the demo.
internal class Program
{
static void Main(string[] args)
{
Example();
Console.ReadLine();
}
private static void Example()
{
Person magnus = new(FirstName: "Magnus", LastName: "Hedlund");
Person terry = new("Terry", "Adams");
Person charlotte = new("Charlotte", "Weiss");
Person arlene = new("Arlene", "Huff");
List<Person> people = new() { magnus, terry, charlotte, arlene };
List<Pet> pets = new()
{
new(Name: "Barley", Owner: terry),
new("Boots", terry),
new("Whiskers", charlotte),
new("Blue Moon", terry),
new("Daisy", magnus),
};
// Create a list where each element is a strong type
// that contains the person's first name and a collection of
// pets that are owned by them.
var query =
from person in people
join pet in pets on person equals pet.Owner into gj
select new PersonPetContainer(person.FirstName, gj);
foreach (var item in query)
{
// Output the owner's name.
Console.WriteLine($"{item.OwnerName}:");
// Output each of the owner's pet's names.
foreach (var pet in item.Pets)
{
Console.WriteLine($" {pet.Name}");
}
}
}
}
public record PersonPetContainer(string OwnerName, IEnumerable<Pet> Pets);
public record Person(string FirstName, string LastName);
public record Pet(string Name, Person Owner);