2012-01-27 3 views
41

У меня есть следующий фрагмент кода в моей LINQ:C# || оператор не работает с обнуляемыми булевыми

where (tf.Shipped || tf.Ordered || tf.Processed) 

Обратите внимание, что Отправляется, упорядоченное и плавленое все обнуляемых булевы поля

Я получаю следующее сообщение:

Оператор || не может применяться к операндам типа «bool?» и 'bool?'

Не знаете, как разрешить это как да, они должны быть обнуляемыми булерами, и мне нужно использовать OR (||).

+0

В чем смысл нулевого значения Boolean? Серьезный вопрос. – DoctorMick

+4

@DoctorMick Тонны использования. Скажем, у меня есть форма оценки состояния здоровья, которая спрашивает, прошел ли у пациента осмотр простаты. Это не касается женщин. Это не «истина» или «ложь». Это «null» - для N/A в этом случае. – Yuck

+0

@DoctorMick или просто True/False/Неизвестно. – adelphus

ответ

103

Сделайте шаг назад и думать об этой проблеме. Вам нужна коллекция виджетов, где был заказан виджет, или был отправлен виджет, или виджет был обработан.

Есть четыре возможных состояния для познания «заказал»:

  • этот виджет был заказан , и я знаю, что (правда)
  • этот виджет был не заказывали , и я знаю, что (ложь)
  • этот виджет был заказан , но я не знаю, что (нуль)
  • этот виджет был не заказывали , но я не знаю, что (null)

Существует четыре состояния, но возможны только три значения. Поэтому, если «упорядоченное» находится в нулевом состоянии , вы не знаете, должно ли оно быть включено в результаты запроса или нет.

Компилятор тоже этого не знает.

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

Что вам нужно сделать, это сказать что делать в случае, если вы не знаете ответа. Запрос «всех виджетов, которые были заказаны, отправлены или обработаны», невозможно, потому что некоторые виджеты мы не знаем, были ли они заказаны, отправлены или обработаны, и поэтому мы не знаем, включать их или нет.Но запрос «все виджеты , что я знаю было приказано, или , что я знаю были отправлены, или , что я знаю были обработаны» запрос, который компилятор может иметь смысл:

where (tf.Shipped ?? false) || (tf.Ordered ?? false) || (tf.Processed ?? false) 

Это означает «если я не знаю, было ли отправлено и т. Д., Предположим, что это не так».

Вместо этого вы могли бы хотеть запрос «все виджеты, которые определенно были, или, возможно, были отправлены, упорядоченный или переработанном:

where (tf.Shipped ?? true) || (tf.Ordered ?? true) || (tf.Processed ?? true) 

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

+10

+1 Этот ответ объясняет, в чем проблема и как ее решить. Это должен быть принятый ответ. –

+0

Уважаемые книжники, пожалуйста, добавьте этот ответ в канон. – hemp

+0

Вы также можете использовать 'where (tf.Shipped | tf.Ordered | tf.Processed) ?? false' или 'где (tf.Shipped | tf.Ordered | tf.Processed) ?? true', если вы этого предпочтете. C# определяет оператор '|' специально для нулевых булевых операндов, поэтому он не просто снятый оператор. –

5
where ((tf.Shipped.HasValue && tf.Shipped.Value) 
     || (tf.Ordered.HasValue && tf.Ordered.Value) 
     || (tf.Processed.HasValue && tf.Processed.Value)) 
+5

'.HasValue! = .Value' – Nate

+3

Интересное решение, время выполнения не сработает с ошибкой null.Value', потому что он не будет проверять правильную сторону оператора '&&' оператора, если '.HasValue' (левая сторона) является' false'. –

+0

Чтобы объяснить комментарий Томислава Марковского, нужно понимать, что если все значения равны нулю, то ни одно из значений не является истинным, и, следовательно, OR из 3 False-операторов False. Аналогично, если HasValue является False, оператор AND всегда False, среда выполнения знает это, и именно по этой причине вы можете проверить значение ссылки, имеющей значение Null. –

18

Необходимо обеспечить, чтобы выражение никогда не было null. Вы можете сделать это с помощью оператора нуль-Coalesce, ??:

where ((tf.Shipped ?? false) || (tf.Ordered ?? false) || (tf.Processed ?? false)) 
1
where ((tf.Shipped.HasValue && tf.Shipped.Value) 
    || (tf.Ordered.HasValue && tf.Ordered.Value) 
    || (tf.Processed.HasValue && tf.Processed.Value)) 
+0

Немного сложно читать IMO – CodesInChaos

+0

@CodeInChaos Это, но смысл явно. – Nate

39

Попробуйте

where (tf.Shipped == true || tf.Ordered == true || tf.Processed == true) 
+0

Почему? так? ....... – Sung

+3

Заставляет результат bool (от bool?). –

+0

И тогда есть '!! x', что эквивалентно' x == true'. –

2

Вы также можете используйте GetValueOrDefault в вашем конкретном случае.

where (tf.Shipped.GetValueOrDefault() 
    || tf.Ordered.GetValueOrDefault() 
    || tf.Processed.GetValueOrDefault()) 
+0

Обратите внимание, что это не будет работать в контексте запроса Entity Framework. – SandRock

Смежные вопросы