Toby
Toby

Reputation: 10144

How to null coalesce for Boolean condition?

I'm trying to safely check if an IList<> is not empty.

var Foo = Bar.GimmeIListT(); // Returns an IList<SomeObject>
if (Foo?.Any())
    // Do cool stuff with items in Foo

But there is an error with the condition:

Cannot implicitly convert 'bool?' to 'bool'. An explicit conversion exists (are you missing a cast?)

So it seems the condition evaluates to a nullable bool, so I try

if (Foo?.Any().Value())

But this is no good either:

'bool' does not contain a definition for 'Value' and no extension .... blah blah blah

So in the first instance it complains that it is a nullable bool but in the second it complains that it isn't.

As another avenue I try:

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

This works - but it shouldn't because this uses an implicit conversion which the first message said it didn't want!

What is going on? What is the correct way to do this?

Upvotes: 16

Views: 12892

Answers (4)

Tim Schmelter
Tim Schmelter

Reputation: 460018

You can compare with the bool? if you use ==, that's indeed the best/simplest approach:

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

as to the why it's not allowed in an if but with ==, Jon Skeet can explain it much better:

There's no implicit conversion from Nullable<bool> to bool. There is an implicit conversion from bool to Nullable<bool> and that's what happens (in language terms) to each of the bool constants in the first version. The bool operator==(Nullable<bool>, Nullable<bool>) operator is then applied. (This isn't quite the same as other lifted operators - the result is just bool, not Nullable<bool>).

In other words, the expression fred == false is of type bool, whereas the expression fred is of type Nullable<bool> hence you can't use it as the "if" expression.

So the if allows only bool and you have a bool?, but the == operator converts the bool to a bool? and you can compare two bool?.

Upvotes: 19

Rashid Ali
Rashid Ali

Reputation: 617

more syntactic sugar, the null-coalescing operator. C# 8.0 or later

if (Foo?.Any() ?? false) { }

Upvotes: 3

Stephan Bauer
Stephan Bauer

Reputation: 9249

Any() returns bool but Foo?.Any() will return bool?

So Foo?.Any().Value won't compile since Any() returns a bool that doesn't have a member Value.

If Foo is null, Any() won't be executed because the statement will return null without interpreting the part behind the ?. operator.

But if you put Foo?.Any() in paranthesis, you are able to work with the result of type bool? and check it via Value or GetValueOrDefault():

(Foo?.Any()).GetValueOrDefault()

Upvotes: 3

Ian
Ian

Reputation: 30813

Edit:

It seems like the cause of the bool? is the Foo?.Any() itself. If you do not want to compare it with true, I would suggest you to have temporary variable:

bool? any = Foo?.Any(); 
if (any.Value) ...

Alternatively, if the object is a class, you could use FirstOrDefault() != null as checking condition. It won't take time because it will only get the first object:

if (Foot?.FirstOrDefault() != null)...

I will go with the temporary variable or the Foo?.Any() == true option though.

Original:

Note: It is to my surprise too that if (a?.Any()) cannot be followed by .Value() or .Value(!).

I think what you need is Value (property) without () (method):

if (Foo?.Any()?.Value) ... 

bool? has .Value (property) which is a bool.

Upvotes: 3

Related Questions