C# adding string + null doesn't throw an error?
As a programmer I would have expected this to throw an exception. Is there a reason why it treats null as ""?
string s = "hello";
string t = null;
Console.WriteLine(s + t);
Output:
开发者_C百科hello
Just to emphasise my question, do you know why the decision to turn null into String.Empty was made? I was expecting some string to be added but there was a problem further back where it wasn't retrieving it properly and it came back with null. The problem went unnoticed!
Here's a pseudocode of why I think it is bad (and why I was shocked to discover no error):
You can assume I overloaded ToString to give the name of the person or details about them.
Person p = PersonDatabase.GetForName("Jimmy Gibbs");
Console.WriteLine("Name is: " + p.ToString());
Throws an exception because p is null
String p = PersonDatabase.GetForName("Jimmy Gibbs").Name;
Console.WriteLine("Name is: " + p);
Doesn't throw an exception, even though p is null (it treats it as "").
(If you want to be picky and say I won't be able to get Name as GetforName will be null, think of it as this:)
String p = PersonDatabase.GetNameFromID(1234); // Returns a string or null if not found
Console.WriteLine("Name is: " + p);
(If you use this value in a list or array you'll end up with a blank entry which is what broke for me, it was creating javascript and trying to get element by ID of "")
From the C# Language Specification:
7.8.4 Addition operator
String concatenation:
string operator +(string x, string y); string operator +(string x, object y); string operator +(object x, string y);
These overloads of the binary + operator perform string concatenation. If an operand of string concatenation is null, an empty string is substituted. Otherwise, any non-string argument is converted to its string representation by invoking the virtual ToString method inherited from type object. If ToString returns null, an empty string is substituted.
The + operator is emitted as string.Concat in the resulting IL.
s + t = string.Concat(s, t)
and when looking at the implementation it checks whether arguments are null and returns string.Empty:
Disassembled with reflector:
[SecuritySafeCritical]
public static string Concat(string str0, string str1)
{
if (IsNullOrEmpty(str0))
{
if (IsNullOrEmpty(str1))
{
return Empty;
}
return str1;
}
if (IsNullOrEmpty(str1))
{
return str0;
}
int length = str0.Length;
string dest = FastAllocateString(length + str1.Length);
FillStringChecked(dest, 0, str0);
FillStringChecked(dest, length, str1);
return dest;
}
When thinking about design decision that was made, we should look not only at plus operator for Strings but also at related classes and methods, e.g. String.Concat(String, String) and StringBuilder.Append(String). Those classes are part of Base Class Library which in widely used in other languegges (e.g. Visual Basic and F#).
From language and platform design perspective, all those methods should behave in a consistent faction (i.e. treat null in the same way). I see three possible options:
Throw exception
This is a "safe" solution since it's not clear what to do with null. As a tradeoff, it would require a more defensive style of programming and more verbose code.
Use some representation for null e.g.
<null>
,null
or[null]
(Java-style)This is an outcome that you expected. It is not clear why this should happen and how exactly null should be represented.
Treat null in the same fashion as empty string (.NET-style)
The idea behind it is that textual representation of null (i.e. an object that is missing) is an empty string. In that case, a programmer can exploit this behavior and write shorter code. On the other hand, it can hide bugs.
Some decision had to be made and I think that there's no obvious choice. Expected behavior in C# and other .NET languages is clearly documented and it's consistent across all the methods that deal with concatenation.
In string concatenation operations, the C# compiler treats a null string the same as an empty string, but it does not convert the value of the original null string. Additional information here http://msdn.microsoft.com/en-us/library/aa691375(VS.71).aspx
If I have an Orange and add another Orange, I now have two oranges.
If I have an Orange and add NOTHING, I still have an orange.
To me adding NULL to a string and getting the original string seems perfectly intuitive and semantic. NullReferenceExceptions should be reserved for when accessing Properties or instance methods on instances that don't exist, eg.
string myString = null;
string lowerCaseString = myString.ToLower();
Would understandably throw a NullReferenceException because I'm trying to access the ToLower() instance method on a reference that doesn't exist hence Null Reference Exception (ie. there's a thing on the Stack, but nothing on the Heap).
Having NULL string concat operations throw exceptions would mean tonnes of extra defensive NULL code checks when dealing with strings, which are annoying. Sorry, but I happen to agree with how C#.NET handles this. Doesn't Java do the same?
If you want to check if a string contains a value then use String.IsNullOrEmpty(myString);
or String.IsNullOrWhitespace(myString);
(only in .NET 4.0)
User defined operators are just static methods and of course can accept null
parameters. This is for example really useful for delegates.
So string accepting null
is no technical but a design decision. And it's probably sometimes useful to treat null
as "" since a lot of user code treats them the same.
Actually this is how strings are represented.... nothing wrong there. null is used as a termination character.
For example:
string a: "blahblah[null]" So whatever reads the string knows to stop at null.
so then when you create a string like this: string b: "[null]" it is perfectly valid.
Now, there are no characters before null. so when your program starts reading the string it encounters null (perfectly valid) and stops.... thus... empty string!!
精彩评论