7

I have the following code:

if (Model.Products?.Cards?.Any())
{
}

If I try this it throws an error:

Cannot convert bool? to bool

Having searched for this this I'm not sure why the error is thrown, where as it will allow me to do

if (Model.Products?.Cards?.Count > 0)
{
}

Why am I unable to use .Any() in this case - why is it classed as a nullable bool yet the count isn't a nullable int?

Pete
  • 57,112
  • 28
  • 117
  • 166
  • 5
    The count *is* a nullable int. –  Apr 17 '18 at 14:36
  • 3
    try `if (Model.Products?.Cards?.Any() == true)` – tom.maruska Apr 17 '18 at 14:36
  • 5
    IIRC that's because you're using the null propagation operator `?`, so the result could either be `null` or the result of `Any()`. – bassfader Apr 17 '18 at 14:37
  • 3
    Your question is hard to answer because it contains false assumptions. – Eric Lippert Apr 17 '18 at 14:38
  • @hvd that makes sense then - just that when my intellisense was over it it still said it was an int rather than nullable int – Pete Apr 17 '18 at 14:38
  • Also, "why" questions are hard to answer. Are you asking what line of the specification justifies this behaviour? Are you asking what design factors led this design to be specified? What precisely is your question? – Eric Lippert Apr 17 '18 at 14:39
  • @Eric Lippert: In my experience, unless they ask either "why does the spec say X" or "what were the design decisions behind X", most askers are happy with a spec citation. If they don't state that they were interested in the design decisions, though, that's on them. – BoltClock Apr 17 '18 at 14:42
  • @EricLippert I was just wondering why count wasn't classed as a nullable int - but it turns out my intellisense was not looking at it correctly or not clever enough to determine that as it followed the question mark it becomes nullable – Pete Apr 17 '18 at 14:46
  • 2
    It should be noted that using the null-conditional operator `?.` anywhere in the chain will cause the type to be nullable. So `Model?.Products.Cards.Any()` would also be a `Nullable`. – juharr Apr 17 '18 at 14:48
  • @juharr good to know - that was what I wasn't sure on now I can do my ifs properly! :) – Pete Apr 17 '18 at 14:49
  • 1
    Also keep in mind that when comparing a `bool?` to either `true` or `false` will return `false` when it's null for both cases. I personally prefer the `?? true` as that states how you want nulls to be handled. – juharr Apr 17 '18 at 14:51

1 Answers1

15

Simply because it is valid do a greater than on a Nullable<int> and int:

if (null > 0)
{
}

null is considered a Nullable<int> here, and comparing Nullable<int> with int is okay. (Required reading: How does comparison operator works with null int?)

But not a if (null). An if statement required a boolean.

The required workaround could be:

if (Model.Products?.Cards?.Any() ?? false)
{ }
Patrick Hofman
  • 153,850
  • 22
  • 249
  • 325
  • 1
    Ah right, along with @hvd's comment this explains it. I'll accept when it lets me. Ta :) – Pete Apr 17 '18 at 14:39
  • As a workaround you could do `if (Model.Products?.Cards?.Any() == true)`, as a null bool? compared with true would give false, and that reads a little more easily – LordWilmore Apr 17 '18 at 14:51
  • 1
    @LordWilmore The problem with that is you might think that changing it to `== false` will give the inverse, but it will not as either way a `null` would result in `false` when compared to a `bool`. `?? false` is specifically stating how you want to handle a `null` value which IMHO is the more correct way to deal with this. – juharr Apr 17 '18 at 15:03
  • @juharr that is a very good point, but rather than deleting my comment I will leave it there so that your response remains in context, as I'm sure it will help people in the future – LordWilmore Apr 17 '18 at 15:04
  • ... or `if (Model.Products?.Cards?.Any().GetValueOrDefault())` or (I personally don't like that but - `if (Model.Products?.Cards?.Any() == true)`) – Zohar Peled Apr 17 '18 at 15:15