Why does the compiler still complain?
This has to do with how nullable objects work in C#. The ?
operator denoting that an object can be null basically tells the compiler 'Hey compiler - this object might be null, and that's okay.'
What this does for you, for as an example with bool?
is allow you to denote a state that is not normally intended.
Normally a bool
can only be true
and false
and if it was never initialized it could be null
. If the bool
was never initialized accessing it's value would throw an NullReferenceException
.
Meanwhile bool?
(denoting nullable bool) says to the compiler 'if the bool is null, treat null
as it's value, instead of throwing an exception and complaining it doesn't have a value.'(in a simplified sense)
The trick with using nullable types, is that they are not implicitly treated like their non-nullable types. They're basically completely different objects, until you say so.
When you think about it it makes a lot of sense. It would be pretty weird if you could set a normal bool, like bool isLightOn = true;
and set it to isLightOn = null;
, what would that even mean? Does the light turn off, no that's what false would be.., would it flash the light on and off? The compiler has no clue what you intend to happen when you set a variable to a value that variable doesn't normally use(like null
). That's a good thing! It would cause all sorts of weird issues.
This leads into the issue you are having.
bool? isLightOn = false;
// compiler checks to see if a bool? can have a null state
// it determines that bool? can be true, false, or null
// it says this line is okay
if(isLightOn != null)
{
// compiler says the variable isn't null,
// but it still CAN be null, for example, if something within this code block changes it's value,
// or if that variable is accessed by another thread
// becuase of this the compiler will not consider this light
// as either true, false(a normal bool) it says 'there's still
// a possibility that by the time it's used it may not be
// either true, or false, therefor it should be considered as
// being maybe null in my eyes(the compiler).'
// compiler checks to see if the object you're passing as a parameter is a valid object
// compiler sees that your object can be true, false, or null
// compiler says 'if i give this method this object without asking the programmer if it's okay, it may break the program becuase the method doesn't know how to deal with null values'
TestLight(isLightOn);
// compiler checks to see if the object you're passing as a parameter is a valid object
// compiler sees that the programmer explicitly told it to ignore the null value and treat is as if it were false, and allows you to pass that variable as parameter
TestLight((bool)isLightOn);
}
void TestLight(bool lightOn)
{
}
When you check a nullable object if it's null, that just checking it's value. Since that's a valid state for the object to be in, the compiler goes about it's day and doesn't complain.
When you try actually use that value for something that uses a non-nullable object as a parameter, we run into that issue of, how is the compiler supposed to know what you want to do if the null
object state isn't a valid state for that object?
So it treats the nullable and non-nullable versions of your object as completely different types, BUT with an explicit cast between the two.
The reason for this can be boiled down to you're trying to use a variable in a way that would lose information, or a lossy operation, if you will.
The compiler wont make an asumption that you want to ignore a valid value for the nullable object.
It forces you to say 'hey compiler, treat this nullable object like a non-nullable object, if it's value isn't expected, change it to an expected value(default). For bool?
if the valid value was null
and you said 'treat it like a non-nullable bool' (by using explicit casting (bool)bool?
, the compiler would say 'Okay! null
is basically default
so that's it's new value when you pass it as a parameter'.