65

I have this very simple example:

class Program
{
    class A
    {
        public bool B;
    }

    static void Main()
    {
        System.Collections.ArrayList list = null;

        if (list?.Count > 0)
        {
            System.Console.WriteLine("Contains elements");
        }

        A a = null;

        if (a?.B)
        {
            System.Console.WriteLine("Is initialized");
        }
    }
}

The line if (list?.Count > 0) compiles perfectly which means that if list is null, the expression Count > 0 becomes false by default.

However, the line if (a?.B) throws a compiler error saying I can't implicitly convert bool? to bool.

Why is one different from the other?

DavidRR
  • 18,291
  • 25
  • 109
  • 191
Dee J. Doena
  • 1,631
  • 3
  • 16
  • 26

2 Answers2

79
Community
  • 1
  • 1
Heinzi
  • 167,459
  • 57
  • 363
  • 519
  • 7
    Thanks. I didn't realize that `list?.Count` basically becomes `int? tmp = list?.Count` and then of course `tmp > 0` evaluates to false. This was the missing piece. – Dee J. Doena Jun 29 '16 at 15:35
  • 1
    An important point is "if, however, requires a bool". This is why one can express `a?.B == true` and it should compile. As obvious as that is, it can elude someone looking too closely at syntax. – Adam Caviness Aug 25 '16 at 18:35
41

In your first case (list?.Count) the operator returns an int? - a nullable int.
The > operator is defined for nullable integers so that if the int? has no value (is null), the comparison will return false.

In your second example (a?.B) a bool? is returned (because if a is null, neither true nor false but null is returned). And bool? cannot be used in an if statement as the if statement requires a (non-nullable) bool.

You can change that statement to:

if (a?.B ?? false)

to make it work again. So the null-coalescing operator (??) returns false when the null-conditional operator (?.) returned null.

Or (as TheLethalCoder suggested):

if (a?.B == true)
René Vogt
  • 43,056
  • 14
  • 77
  • 99
  • 3
    Would `if (a?.B == true)` give the same effect? – TheLethalCoder Jun 29 '16 at 15:37
  • 4
    @TheLethalCoder While C# limits `bool` values to `false` and `true`, the .NET Framework does not, and non-C# methods may give you what can be in pseudo-C# as `(bool) 2`. Such a value is true enough to enter an `if` block if used as the condition, but does not compare equal to `true`. –  Jun 29 '16 at 17:16
  • 2
    Whether `if (a?.B == true)` works or not, when I see it, I have the gut instinct to chime in "don't compare booleans to true (or false), use them directly," as would normally be appropriate when someone writes `if (someCondition == true)` instead of `if (someCondition)`. I'm not sure what to make of a construction that ends up encouraging `(... == true)`. – Joshua Taylor Jun 29 '16 at 19:17
  • @JoshuaTaylor it's not comparing a `bool` to `true`, but a `bool?` – René Vogt Jun 29 '16 at 19:29
  • 2
    @RenéVogt Yes, I understand that; my point is that it's jarring to see a place where `== true` *is* the right thing. – Joshua Taylor Jun 29 '16 at 19:36
  • Also will (b?.A == false) give a similar effect? – Krish Munot Jul 23 '16 at 17:42
  • @KrishMunot what do you mean? there is no variable called `b` in the question. – René Vogt Jul 23 '16 at 19:32
  • @RenéVogt They obviously mistyped :-/ (a?.B == false) works as well. The issue here is null. – Saturn K Aug 07 '17 at 22:31