Reputation: 10144
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
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>
tobool
. There is an implicit conversion frombool
toNullable<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 justbool
, notNullable<bool>
).In other words, the expression
fred == false
is of typebool
, whereas the expressionfred
is of typeNullable<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
Reputation: 617
more syntactic sugar, the null-coalescing operator. C# 8.0 or later
if (Foo?.Any() ?? false) { }
Upvotes: 3
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
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