Здесь есть несколько проблем. Во-первых, оператор Where не создает список объектов. Это выражение выражения.
Операторы выражений оцениваются на лету, поэтому изменения в создаваемых объектах отбрасываются при каждом запуске этого оператора. Хотите верьте, хотите нет, но это желаемый результат. Это позволяет вам обрабатывать сложные вложенные выражения более эффективным и элегантным образом.
Лучший способ ответить на ваш вопрос - проанализировать то, что вы написали, и переработать часть кода, чтобы показать вам лучший способ.
В вашем коде:
List<Apple> apples = ...
var selectableApples = apples.Select(a => new SelectableApple { SelectedByPerson = null, Apple = a });
foreach (Person person in persons)
{
foreach (var unselectedApple in selectableApples.Where(aa => aa.SelectedByPerson == null))
{
// This will ideally give all apples to the first person who
// meets the conditions. As such this if condition can be moved
// out side of the above the foreach loop.
if (/*the person satisfies some conditions*/)
{
// This gets executed like 100 times:
unselectedApple.SelectedByPerson = person;
}
}
}
foreach (var selectedApple in selectableApples.Where(aa => aa.SelectedByPerson != null))
{
Unreachable code - the collection is empty... WTF???
}
Так что, если мы переделаем этот код так, чтобы оператор if находился вне внутреннего цикла. Ваш код будет делать то же самое логично. Имейте в виду, что это еще не решает проблему, но приближает вас на один шаг. Вот как будет выглядеть код:
List<Apple> apples = ...
var selectableApples = apples.Select(a => new SelectableApple { SelectedByPerson = null, Apple = a });
foreach (Person person in persons)
{
// Now we can see that since this will all apples to the first person
// who satisfies the below conditions we are still doing to much. And it
// still does not work.
if (/*the person satisfies some conditions*/)
{
foreach (var unselectedApple in selectableApples.Where(aa => aa.SelectedByPerson == null))
{
// This gets executed like 100 times:
unselectedApple.SelectedByPerson = person;
}
}
}
foreach (var selectedApple in selectableApples.Where(aa => aa.SelectedByPerson != null))
{
Unreachable code - the collection is empty... WTF???
}
Теперь мы начали группировать вещи, чтобы можно было увидеть более простой ответ. Так как утверждение if означает, что только тот, кто выполнит условие, будет первым, кто получит все яблоки. Итак, давайте избавимся от внешнего цикла foreach и сконцентрируем его до LINQ.
List<Apple> apples = ...
var selectableApples = apples.Select(a => new SelectableApple { SelectedByPerson = null, Apple = a });
var selectedPerson = persons.Where(p => /*the person satisfies some conditions*/).First()
if(selectedPerson != null)
{
foreach (var unselectedApple in selectableApples.Where(aa => aa.SelectedByPerson == null))
{
// This gets executed like 100 times:
unselectedApple.SelectedByPerson = person;
}
}
foreach (var selectedApple in selectableApples.Where(aa => aa.SelectedByPerson != null))
{
Unreachable code - the collection is empty... WTF???
}
Глядя на приведенный выше код, мы теперь видим, что внутренний цикл - это всего лишь модификация исходного выбора. Итак, давайте посмотрим на это:
List<Apple> apples = ...
var selectedPerson = persons.Where(p => /*the person satisfies some conditions*/).First()
var selectableApples = apples.Select(a => new SelectableApple { SelectedByPerson = selectedPerson, Apple = a });
foreach (var selectedApple in selectableApples.Where(aa => aa.SelectedByPerson != null))
{
// This should now run provided that some person passes the condition.
}
Теперь ваш код будет работать так, как вам нужно, и вы сможете воспользоваться отложенной загрузкой и оптимизацией зацикливания, предоставляемыми в LINQ.