Если заявление внутри лямбды для всего запроса - PullRequest
3 голосов
/ 30 ноября 2011

Можно ли сделать это утверждение одним лямбда-выражением?

if (filter.SubFormId.HasValue)
{
    query = query.Where(c => c.SubFormId == filter.SubFormId);
}

Ответы [ 3 ]

9 голосов
/ 30 ноября 2011

Будьте очень осторожны с такого рода запросом . Предложение where связано с фильтром variable , а не с текущим значением .

Оригинальный код:

var query = from form in forms select form;
var filter = new Filter();
filter.SubFormId = 123;
if (filter.SubFormId.HasValue)
{
    query = query.Where(c => c.SubFormId == filter.SubFormId);
}
filter = null;
foreach(var matchingForm in query)
{ ... }

Этот код вылетает. В запросе используется текущее значение фильтра, а не значение, которое было при создании запроса.

Версия Джареда не лучше:

var query = from form in forms select form;
var filter = new Filter();
filter.SubFormId = 123;
query = query.Where(c => 
  !filter.SubFormId.HasValue || c.SubFormId == filter.SubFormId);
filter = null;
foreach(var matchingForm in query)
{ ... }

Это тоже дает сбой.

Ваша версия и версия Джареда также имеют различную семантику, если фильтр изменен другими способами:

Оригинальный код:

var query = from form in forms select form;
var filter = new Filter();
filter.SubFormId = null;
if (filter.SubFormId.HasValue)
{
    query = query.Where(c => c.SubFormId == filter.SubFormId);
}
filter.SubFormId = 123;
foreach(var matchingForm in query)
{ ... }

Это соответствует каждой форме. Вы никогда не добавляли предложение Where.

Версия Джареда делает что-то другое:

var query = from form in forms select form;
var filter = new Filter();
filter.SubFormId = null;
query = query.Where(c => 
  !filter.SubFormId.HasValue || c.SubFormId == filter.SubFormId);
filter.SubFormId = 123;
foreach(var matchingForm in query)
{ ... }

Соответствует только формам, у которых subformId равен 123. Версия Джареда сопоставляется с текущим значением идентификатора подчиненной формы фильтра, если он есть, независимо от того, был ли он при создании запроса.

Помните, запросы - это объекты, которые представляют запрос . Когда вы выполняете запрос, запрос выполняется заново с нуля, и его предложения оцениваются по значениям current переменных, которые закрыты в запросе, а не по снимку значений переменных как они существовали, когда был создан запрос. Запросы имеют живое, актуальное представление переменных.

Итак, допустим, я также возвращаю этот запрос, что позволяет оценивать запрос вне метода. Произойдет ли этот сбой, так как фильтр выйдет за рамки?

Краткий ответ:

нет.

Более длинный ответ:

Это дубликат этого вопроса:

Действие / Лямбда-выражение Управление памятью Вопрос

Подробности см. В моем ответе.

Длинный ответ:

Вы путаете область с продолжительностью жизни - распространенная ошибка. Scope - это просто концепция времени компиляции; область действия локальной переменной - это область текста программы, в которой эта переменная может указываться по ее имени. Время жизни переменной является чисто концепцией времени выполнения; время жизни локальной переменной - это период времени, в течение которого хранилище мусора известно как действительное.

Область и время жизни часто связаны; хотя управление логически находится в той части текста программы, в которой находится локальная область, известно, что она жива. Локали, используемые в запросах, лямбда-выражениях, блоках итераторов и асинхронных блоках, имеют увеличенное время жизни, так что даже когда контроль покидает область действия локального, локальный объект все еще жив. Местный житель остается живым, по крайней мере, до тех пор, пока запрос, лямбда и т. Д. Не будет мертвым.

В некоторых случаях, к сожалению, местный житель может жить дольше; см. связанный вопрос выше для примера. Подробное обсуждение этой проблемы см. В следующем вопросе:

C # Действие, Закрытие и сборка мусора

3 голосов
/ 30 ноября 2011

Попробуйте следующее

query = query.Where(c => 
  !filter.SubFormId.HasValue || c.SubFormId == filter.SubFormId);
1 голос
/ 30 ноября 2011

Вы не указали, каким должно быть значение query, если условие не true

Но это, вероятно, близко к тому, что вы ожидаете

query = query.Where(c => 
      filter.SubFormId.HasValue && c.SubFormId == filter.SubFormId);

В результате получается пустое перечисляемое значение, если SubFormId равно null

query = query.Where(c => 
      filter.SubFormId.HasValue? c.SubFormId == filter.SubFormId : true);

В результате нефильтрованный список


Редактировать Я хочу второй комментарий Марка, это очень близко к

query = filter.SubFormId.HasValue
     ? query.Where(c => c.SubFormId == filter.SubFormId) 
     : query;

, который в значительной степени ваш оригинальный код. Ваш оригинальный код будет более эффективным, чем принудительная версия в стиле Linq.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...