可以将文章内容翻译成中文,广告屏蔽插件可能会导致该功能失效(如失效,请关闭广告屏蔽插件后再试):
问题:
What is the reason null
doesn't evaluate to false
in conditionals?
I first thought about assignments to avoid the bug of using =
instead of ==
, but this could easily be disallowed by the compiler.
if (someClass = someValue) // cannot convert someClass to bool. Ok, nice
if (someClass) // Cannot convert someClass to bool. Why?
if (someClass != null) // More readable?
I think it's fairly reasonable to assume that null
means false
. There are other languages that use this too, and I've not had a bug because of it.
Edit: And I'm of course referring to reference types.
A good comment by Daniel Earwicker on the assignment bug... This compiles without a warning because it evaluates to bool
:
bool bool1 = false, bool2 = true;
if (bool1 = bool2)
{
// oops... false == true, and bool1 became true...
}
回答1:
It's a specific design feature in the C# language: if
statements accept only a bool
.
IIRC this is for safety: specifically, so that your first if (someClass = someValue)
fails to compile.
Edit: One benefit is that it makes the if (42 == i)
convention ("yoda comparisons") unnecessary.
回答2:
"I think it's fairly reasonable to assume that null means false"
Not in C#. false is a boolean struct, a value type. Value types cannot have a null value. If you wanted to do what you achieved, you'd have to create custom converters of your particular type to boolean:
public class MyClass
{
public static implicit operator bool(MyClass instance)
{
return instance != null;
}
}
With the above, I could then do:
if (instance) {
}
etc.
回答3:
"I think it's fairly reasonable to assume that null means false"
I don't agree. IMHO, more often than not, false means "no". Null means "I don't know"; i.e. completely indeterminate.
回答4:
One thing that comes to mind what about in the instance of a data type, like int? Int's can't be null, so do they always evaluate to true? You could assume that int = 0 is false, but that starts to get really complicated, because 0 is a valid value (where maybe 0 should evaluate to true, because the progammer set it) and not just a default value.
There are a lot of edge cases where null isn't an option, or sometimes it's an option, and other times it's not.
They put in things like this to protect the programmer from making mistakes. It goes along the same line of why you can't do fall through in case statements.
回答5:
Just use if(Convert.ToBoolean(someClass))
http://msdn.microsoft.com/en-us/library/wh2c31dd.aspx
Parameters
value Type: System.Object An object that implements the
IConvertible interface, or null.
Return Value
Type: System.Boolean true or false,
which reflects the value returned by
invoking the IConvertible.ToBoolean
method for the underlying type of
value. If value is null, the method
returns false
回答6:
As far as I know, this is a feature that you see in dynamic languages, which C# is not (per the language specification if
only accepts bool
or an expression that evaluates to bool
).
I don't think it's reasonable to assume that null
is false
in every case. It makes sense in some cases, but not in others. For example, assume that you have a flag that can have three values: set, unset, and un-initialized. In this case, set would be true
, unset would be false
and un-initialized would be null
. As you can see, in this case the meaning of null
is not false
.
回答7:
Because null and false are different things.
A perfect example is bool? foo
If foo's value is true, then its value is true.
If foo's value is false, then its value is false
If foo has nothing assigned to it, its value is null.
These are three logically separate conditions.
Think of it another way
"How much money do I owe you?"
"Nothing" and "I don't have that information" are two distinctly separate answers.
回答8:
What is the reason null doesn't
evaluate to false in conditionals?
I first thought about assignments to
avoid the bug of using =
instead of
==
That isn't the reason. We know this because if the two variables being compared happen to be of type bool
then the code will compile quite happily:
bool a = ...
bool b = ...
if (a = b)
Console.WriteLine("Weird, I expected them to be different");
If b
is true, the message is printed (and a
is now true, making the subsequent debugging experience consistent with the message, thus confusing you even more...)
The reason null
is not convertible to bool
is simply that C# avoids implicit conversion unless requested by the designer of a user-defined type. The C++ history book is full of painful stories caused by implicit conversions.
回答9:
Structurally, most people who "cannot think of any technological reason null should be equal to false" get it wrong.
Code is run by CPUs.
Most (if not all) CPUs have bits, groups of bits and interpretations of groups of bits. That said, something can be 0
, 1
, a byte
, a word
, a dword
, a qword
and so on.
Note that on x86 platform, bytes are octets (8 bits), and words are usually 16 bits, but this is not a necessity. Older CPUs had words of 4 bits, and even todays' low-end embedded controllers often use like 7 or 12 bits per word.
That said, something is either "equal", "zero", "greater", "less", "greater or equal", or "less or equal" in machine code. There is no such thing as null
, false
or true
.
As a convention, true
is 1
, false
is 0
, and a null
pointer is either 0x00
, 0x0000
, 0x00000000
, or 0x0000000000000000
, depending on address bus width.
C# is one of the exceptions, as it is an indirect type, where the two possible values 0
and 1
are not an immediate value, but an index of a structure (think enum
in C, or PTR
in x86 assembly).
This is by design.
It is important to note, though, that such design decisions are elaborate decisions, while the traditional, straightforward way is to assume that 0
, null
and false
are equal.
回答10:
C# doesn't make a conversion of the parameter, as C++ does. You need to explicitly convert the value in a boolean, if you want the if
statement to accept the value.
回答11:
It's simply the type system of c# compared to languages like PHP, Perl, etc.
A condition only accepts Boolean
values, null does not have the type Boolean
so it doesn't work there.
As for the NULL example in C/C++ you mentioned in another comment it has to be said that neither C nor C++ have a boolean type (afair C++ usually has a typecast for bool that resolves to an int, but thats another matter) and they also have no null-references, only NULL(=> 0)-pointers.
Of course the compiler designers could implement an automatic conversion for any nullable type to boolean but that would cause other problems, i.e.:
Assuming that foo
is not null
:
if (foo)
{
// do stuff
}
Which state of foo is true?
Always if it's not null?
But what if you want your type to be convertable to boolean (i.e. from your tri-state or quantum-logic class)?
That would mean you would have two different conversions to bool, the implicit and the explicit, which would both behave differently.
I don't even dare to imagine what should happen if you do
if (!!foo) // common pattern in C to normalize a value used as boolean,
// in this case might be abused to create a boolean from an object
{
}
I think the forced (foo == null)
is good since it also adds clarity to your code, it's easier to understand what you really check for.