问题
Coming from Basic boolean logic in C#, I was wondering why:
Dim b As Boolean
Dim obj As Object = Nothing
'followig evaluates to False'
b = DirectCast(Nothing, Boolean)
'This throws an "Object reference not set to an instance of an object"-Exception'
b = DirectCast(obj, Boolean)
A CType(obj, Boolean)
would evaluate to False
(just as CBool(obj))
. I think it is because the compiler uses a helper function, but that is not my theme.
Why does casting Nothing
to Boolean
evaluates to False
, whereas casting an object that is Nothing
to Boolean
throws an Nullreference-Exception? Does that make sense?
[Option Strict ON]
回答1:
Presumably, this is because Nothing in VB.NET is not exactly the same thing as null
in C#.
In the case of value types, Nothing
implies the default value of that type. In the case of a Boolean
, the default value is False
, so the cast succeeds.
One of the primary differences between value types such as Integer or structures and reference types such as Form or String is that reference types support a null value. That is to say, a reference type variable can contain the value Nothing, which means that the variable doesn't actually refer to a value. In contrast, a value type variable always contains a value. An Integer variable always contains a number, even if that number is zero. If you assign the value Nothing to a value type variable, the value type variable just gets assigned its default value (in the case of Integer, that default value is zero). There is no way in the current CLR to look at an Integer variable and determine whether it has never been assigned a value - the fact that it contains zero doesn't necessarily mean that it hasn't been assigned a value.
–The Truth about Nullable Types and VB...
EDIT: For further clarification, the reason the second example throws a NullReferenceException
at run-time is because the CLR is attempting to unbox the Object
(a reference type) to a Boolean
. This fails, of course, because the object was initialized with a null reference (setting it equal to Nothing
):
Dim obj As Object = Nothing
Remember that, as I explained above, the VB.NET keyword Nothing
still works the same way as null
in C# when it comes to reference types. That explains why you're getting a NullReferenceException
because the object you're attempting to cast is literally a null reference. It does not contain a value at all, and therefore cannot be unboxed to a Boolean
type.
You don't see the same behavior when you try to cast the keyword Nothing
to a Boolean, i.e.:
Dim b As Boolean = DirectCast(Nothing, Boolean)
because the keyword Nothing
(this time, in the case of value types) simply means "the default value of this type". In the case of a Boolean
, that's False
, so the cast is logical and straightforward.
回答2:
There's a couple of things you have to realize here.
The first is what others have already pointed out: Nothing
can be interpreted by the VB compiler as simply the Boolean
value False
given the proper context, such as Dim b As Boolean = Nothing
.
This means that when the compiler sees this:
b = DirectCast(Nothing, Boolean)
It sees a literal (Nothing
) and also sees that you want to use this literal as a Boolean
. That makes it a no-brainer.
But now here's the second thing you have to realize. DirectCast
on an Object
is essentially an unboxing operation (for value types). So what needs to happen from the VB compiler's perspective is: there needs to be a Boolean
in that box, or else the operation will fail. Since there is in fact nothing in the box—and this time we're really talking nothing, as in null
—it throws an exception.
If I were to translate this code to C#, it would look like this:
bool b;
object obj = null;
b = (bool)default(bool);
b = (bool)obj;
Hopefully that makes things a bit clearer?
回答3:
There's a difference between using the keyword (literal) Nothing
, and using a reference variable whose value is Nothing
.
In VB.NET, the literal (keyword) Nothing gets special treatment. The
Nothing
keyword can be automatically converted into a value type, using the default value of that type.A reference variable whose value is
Nothing
is different. You don't get the special behaviour.The documentation says DirectCast "requires an inheritance or implementation relationship between the data types of the two arguments".
Clearly
Object
does not inherit from or implementBoolean
, unless you have put a boxedBoolean
into an object variable.
So the code below fails at runtime with an exception.
Dim obj As Object = Nothing
b = DirectCast(obj, Boolean)
回答4:
To get the expected behavior, you need this code:
Dim b As Boolean?
Dim obj As Object = Nothing
b = DirectCast(obj, Boolean?)
The character ?
mean Nullable(of )
.
回答5:
I'm finding that comparing of the Boolean variable to a string of "True", "False" or Is nothing seems to ensure that I get the correct comparisons. I was using a function to return an html string of a div with an image of a checked or unchecked radio button and was having the issue of nothing coming back as false. Using the variable = "True" or "False" string and doing the last check with IS NOTHING helped to resolve that issue.
Dim b as boolean = nothing
response.write CheckValue(b = "True")
response.write (b = "False")
response.write (b is nothing)
Function CheckValue(inVal as boolean) as string
if inVal then
return ("<div><img src="checked.png" ></div>
else
return ("<div><img src="unchecked.png" ></div>
end if
end function
The system seems to do the conversion to string when implicitly compared to a string whereas using the .tostring method just creates an error while allowing the last comparison to actually compare to a value of nothing.
Hopefully that helps somewhat. It at least let me
来源:https://stackoverflow.com/questions/4804318/vb-net-boolean-from-nothing-sometimes-false-sometimes-nullreference-except