You are writing a boolean expression that might look like this:
team.Category == "A Team" && team?.Manager?.IsVietnamVet
public class Manager
{
public bool IsVietnamVet { get; set; }
}
public class Team
{
public string Category { get; set; }
public Manager Manager { get; set; }
}
…and you get an error:
Operator ‘&&’ cannot be applied to operands of type ‘bool’ and ‘bool?’
What is the optimal/cleanest way to handle it?
-
team.Category == "A Team" && (team?.Manager?.IsVietnamVet ?? false)
Is that really readable?
-
team.Category == "A Team" && (team?.Manager?.IsVietnamVet).GetValueOrDefault()
It may not work in LINQ-to-Entities…
-
team.Category == "A Team" && team?.Manager?.IsVietnamVet == true
Would you really write
if (condition == true)
without any hesitation?
Are there any other options? Is it ultimately better to write:
team.Category == "A Team" && team.Manager != null && team.Manager.IsVietnamVet
11
In this particular case, it might be wise to follow the Law of Demeter i.e.
public class Team
{
public bool IsManagerVietnamVet => Manager?.IsVietnamVet ?? false;
}
More generally, if a boolean expression is complex or ugly then there’s nothing to say you couldn’t divide it (or part of it) into a separate statement:
bool isVietnamVet = Manager?.IsVietnamVet ?? false;
if (team.Category == "A Team" && isVietnamVet)
When stepping through code in the debugger, it’s often nicer to have elaborate conditions packaged up into a single bool
just to save a little bit of mouseover-hovering; in fact, it might just be nicer to put the whole thing in a bool
variable.
bool isVietnamVetAndCategoryA = (team.Category == "A Team"
&& Manager?.IsVietnamVet ?? false);
if (isVietnamVetAndCategoryA)
or with LINQ:
var wibble = from flight in airport
from passenger in flight.manifest
let isOnPlane =
(flight.FinishedBoarding && passenger.Flight == flight.FlightNumber)
where !isOnPlane
select passenger;
5
I think option 3 (i.e. == true
) is the cleanest way to test that a bool?
is true
, because it’s very clear about what it does.
In most code x == true
doesn’t make sense, because it’s the same as x
, but that does not apply here, so I think == true
wouldn’t be very confusing.
2
Expanding on Ben Cottrell’s answer, the “Null Object” pattern can help you further.
Instead of returning a null
team/manager, extract ITeam
and IManager
interfaces and return meaningful alternative implementations:
public class NoManager : IManager
{
public bool IsVietnamVet => false;
}
public class NoTeam : ITeam
{
public bool ManagedByVietnamVet => false;
public IManager Manager => new NoManager();
}
Then all of a sudden you can do team.ManagedByVietnamVet
safely.
This of course relies on the upstream provider of team
to be null-safe – but that can be ensured with appropriate testing.
0
I wrote a simple class you could use:
public class MyBool
{
public bool? Value { get; set; }
public MyBool(bool b)
{
Value = b;
}
public MyBool(bool? b)
{
Value = b;
}
public static implicit operator bool(MyBool m)
{
return m?.Value ?? false;
}
public static implicit operator bool?(MyBool m)
{
return m?.Value;
}
public static implicit operator MyBool(bool m)
{
return new MyBool(m);
}
public static implicit operator MyBool(bool? m)
{
return new MyBool(m);
}
public override string ToString()
{
return Value.ToString();
}
}
If reliable to use a custom type, of course.
You can compare MyBool
with both bool
and Nullable<bool>
.
1