13

Why this code works:

if (list?.Any() == true)

but this code doesn't:

if (list?.Any())

saying Error CS0266 Cannot implicitly convert type 'bool?' to 'bool'

So why is it not a language feature making such an implicit conversion in the if statement?

Cornelius Roemer
  • 3,772
  • 1
  • 24
  • 55
Centro
  • 3,892
  • 2
  • 25
  • 31
  • 4
    You mean why doesn't the `if` statement accept a `bool?` condition? It feels to me like it's pretty ambiguous which way you want to go if the result is null. You're defaulting to false (effectively) but in other cases you'd want to default to true. – Jon Skeet Aug 09 '17 at 17:21
  • `list?.Any()` has the potential to be `null` if list is null. And given that Any returns bool it has the potential to return a bool. thus nullable boolean at compile time – Nkosi Aug 09 '17 at 17:21
  • But beyond this, unless Mads or someone else on the C# design team answers, you're basically going to get speculation. – Jon Skeet Aug 09 '17 at 17:21
  • 11
    `if (null == true)` is legal, but `if (null)` isn't. – hatchet - done with SOverflow Aug 09 '17 at 17:24
  • 2
    Note that your final option will throw an exception if `list` is null. That's not good. – Jon Skeet Aug 09 '17 at 17:26
  • Also, for something from person who should know (Eric Lippert): [null is not false pt1](https://blogs.msdn.microsoft.com/ericlippert/2012/03/26/null-is-not-false/) and [null is not false pt2](https://blogs.msdn.microsoft.com/ericlippert/2012/04/12/null-is-not-false-part-two/) – hatchet - done with SOverflow Aug 09 '17 at 17:42
  • see https://softwareengineering.stackexchange.com/questions/313779/optimal-way-to-use-null-conditional-operators-in-boolean-expressions – juFo Jun 21 '19 at 08:05
  • A bit late to the party, but just a note that I would be careful about saying that `if (list?.Any() == true)` _works_. It _works_ in the sense that it compiles, but it is pretty ambiguous code. For example, if `list` is null: Then `if (list?.Any() == true)` and `if (list?.Any() == false)` both evaluate to `false`, meaning that `if ((list?.Any() == true) == (list?.Any() == false)` is `true`. If you change the test to != then `if ((list?.Any() != true) && (list?.Any() != false)` is `true` Yes it technically works, but I would not recommend using code like this. – MG83 Aug 08 '22 at 17:05

1 Answers1

8

An if statement will evaluate a Boolean expression.

bool someBoolean = true;

if (someBoolean)
{
    // Do stuff.
}

Because if statements evaluate Boolean expressions, what you are attempting to do is an implicit conversion from Nullable<bool>. to bool.

bool someBoolean;
IEnumerable<int> someList = null;

// Cannot implicity convert type 'bool?' to 'bool'.
someBoolean = someList?.Any();

Nullable<T> does provide a GetValueOrDefault method that could be used to avoid the true or false comparison. But I would argue that your original code is cleaner.

if ((list?.Any()).GetValueOrDefault())

An alternative that could appeal to you is creating your own extension method.

public static bool AnyOrDefault<T>(this IEnumerable<T> source, bool defaultValue)
{
    if (source == null)
        return defaultValue;

    return source.Any();
}

Usage

if (list.AnyOrDefault(false))
Derrick Moeller
  • 4,808
  • 2
  • 22
  • 48
  • 2
    I interpreted the question as "why doesn't `if` accept a `bool?` condition?" – Jon Skeet Aug 09 '17 at 17:25
  • So the question is why an explicit conversion is ok but the implicit one not? This is not about accepting `bool?` condition. – Centro Aug 09 '17 at 17:37
  • 1
    @Centro Because the explicit conversion will throw an exception if you try to cast `null`. Implicit conversions throwing exceptions should be avoided at all costs, so we can't have the implicit conversion act the same way. We also can't implicitly convert `null` to `false` because that's unreasonable. For example you'd probably want `if( !list?.Any() )` to be the opposite of `if( list?Any() )`. But if `list == null` then both of those would end up being `if( null )`. – Kyle Aug 09 '17 at 17:45
  • I would also add a default value to the defaultValue parameter `public static bool AnyOrDefault(this IEnumerable source, bool defaultValue = false)` so that you can call the method with no parameters like `if (list.AnyOrDefault())` – Bill Lefler Mar 06 '21 at 14:05
  • Another practical reason is: ```if (MyClass?.MyInt > 0)``` resolves to ```if (null > 0)``` which is legal and resolves to ```if (false)```. (Yes the 'greater than' operator allows for comparing an ```int``` to ```null``` or ```int?```). The same goes for all operators, which are defined for ```null```, which seems to go for all standard comparison operators: ```< > == >= =<```... so you can use ```if (MyClass?.MyString == "Hi")``` or from the Question: ```if (MyClass?.MyNullableBool == true)``` – somedotnetguy May 30 '23 at 13:55