Подтвердить что ты не робот

Могу ли я получить доступ к пропущенному "родительскому" элементу SelectMany при использовании точечного синтаксиса в Linq?

В синтаксисе запроса я могу написать

var greendoorsWithRooms = from room in house.roooms
from door in room.doors
where door.Color = green
select new {d=door,r=room}

Есть ли способ, которым я мог бы добиться того же с точным синтаксисом?

var greendoorsWithRooms = house.rooms.SelectMany(room=>room.Doors)
     .Where(door=>door.Color==green)
     .Select(door=>new{ <room is not in scope> }

Я преподаю некоторым не-программистам использовать LINQPad против проприетарной объектной модели, так что нам не нужно создавать графический интерфейс вокруг каждого нечетного случая. Было бы полезно, если бы им не пришлось изучать синтаксис запроса. В настоящее время я предоставил фрагменты, разрешающие это, используя foreach, но вопрос все равно возникает время от времени.

4b9b3361

Ответ 1

Это также возможно (не проверка синтаксиса):

house.rooms.SelectMany(room => room.Doors.Where(door => door.Color==green),
   (room, door) => new { r=room, d=door })

Это this перегрузка SelectMany.

Ответ 2

Все запросы LINQ преобразуются компилятором в точечную нотацию. Свободная нотация - это просто синтаксический сахар.

В спецификациях языка С# перевод "from x1 in e1 from x2 in e2" явно вызывается на стр. 211.

from x1 in e1 from x2 in e2

становится

from * in (e1).SelectMany(x1 => e2, (x1, x2) => new { x1, x2 })

Следуя кулинарной книге, ваш пример будет

from * in house.rooms.SelectMany(room => room.doors, (room, doors) => new { room, doors })

а затем вы завершите преобразование в точечную нотацию, добавив предложения Where и Select. Фактически документация для SelectMany дает ваш запрос в качестве примера!

var query =
    petOwners
    .SelectMany(petOwner => petOwner.Pets,
                (petOwner, petName) => new { petOwner, petName })
    .Where(ownerAndPet => ownerAndPet.petName.StartsWith("S"))
    .Select(ownerAndPet =>
            new
            {
                Owner = ownerAndPet.petOwner.Name,
                Pet = ownerAndPet.petName
            }
    );

Вам просто нужно изменить "владельца" на "комнату" и "домашних животных" на "двери" и изменить состояние фильтра.

Ответ 3

Не идеально, но вы всегда можете использовать анонимные типы в SelectMany: var greendoorsWithRooms = house.rooms.SelectMany(room=> new { Room = room, Doors = room.Doors}) .Where(roomAndDoors=>roomAndDoors.Door.Color==green) .Select(roomAndDoors => ...