ToString on null string - c#

Why does the second one of these produce an exception while the first one doesn't?
string s = null;
MessageBox.Show(s);
MessageBox.Show(s.ToString());
Updated - the exception I can understand, the puzzling bit (to me) is why the first part doesn't show an exception. This isn't anything to do with the Messagebox, as illustrated below.
Eg :
string s = null, msg;
msg = "Message is " + s; //no error
msg = "Message is " + s.ToString(); //error
The first part appears to be implicitly converting a null to a blank string.

because you cannot call instance method ToString() on a null reference.
And MessageBox.Show() is probably implemented to ignore null and print out empty message box.

It is because MessageBox.Show() is implemented with pinvoke, it calls the native Windows MessageBox() function. Which doesn't mind getting a NULL for the lpText argument. The C# language has much stricter rules for pure .NET instance methods (like ToString), it always emits code to verify that the object isn't null. There's some background info on that in this blog post.

As this question ranks quite high on Google for a search for "c# toString null", I would like to add that the Convert.ToString(null) method would return an empty a null string, which is ignored by the messagebox.
However, just to reaffirm the other answers, you can use string.Concat("string", null) in this example.
Edit - modified answer in line with HeyJude's comment below. As pointed out, a method like Convert.ToString(null).Length will throw an exception.

Behind the scenes concat is being called in your follow up question / update E.g
string snull = null;
string msg = "hello" + snull;
// is equivalent to the line below and concat handles the null string for you.
string msg = String.Concat("hello", snull);
// second example fails because of the toString on the null object
string msg = String.Concat("hello", snull.ToString());
//String.Format, String.Convert, String.Concat all handle null objects nicely.

You are trying to execute the ToString() method on a null. You need a valid object in order to execute a method.

The .show function must have null checking and handle it.

Because, the second call is expecting an object of "s" to satisfy a ToString() method request. so, before .Show() is called, the s.ToString() would failed with an attempt to call a method.
Interestingly, While .Show() is implemented correctly, many such methods expect non null instances to be passed in. Usually, that is when you use a NullObject pattern so that the caller should not have to deal with this kind of behavior.

Probably the Show method handles a null value and just shows nothing.
The second use of s - s.ToString() fails because you there is no ToString method to run.

ToString() can't operate on null reference of s vairable
The shortest way
obj?.ToString()
Another correct ways
obj?.ToString() ?? string.Empty
obj?.ToString() ?? "default string value"
https://www.informit.com/articles/article.aspx?p=2421572

Related

Why cannot I use String.Contains() if default string is null?

From MSDN doc:
public bool Contains(
string value
)
Return Value: true if the value parameter occurs within this string, or if value is the empty string (""); otherwise, false.
Exception: ArgumentNullException: value is null.
Example:
string s = string.Empty; //or string s = "";
Console.WriteLine(s.Contains("Hello World!")); //output: False
If I change it to:
try
{
string s = null; //or string s;
Console.WriteLine(s.Contains("Hello World!"));
}
catch (Exception e)
{
Console.WriteLine(e.Message);
}
It'll throw an error message: Object reference not set to an instance of an object since string doesn't have a default value (like "") from Default Values Table (C# Reference),
Please come back to the example, the code will work if I declare s:
string s = "";
Now, Object s is set to an instance of an object.
So, my question is: Does MSDN forgot something like: s cannot be null?
To check it, I've tried:
string s = null;
Console.WriteLine(!string.IsNullOrEmpty(s) ? s.Contains("Hello World!") : false);
It should work.
You changed the value with the instance.
myString.Contains(anotherString)
Here myString is the instance on which you call the method Contains, whereas anotherString is the value passed to the method. If this value is null the method will throw an ArgumentNullException.
When changing the instance to null on the other hand it surely leads to NRE as you canĀ“t call any member on a null-reference. However if you set it to string.empty Contains will return false because the empty string does not contain anything (in particular string.empty does not contain "Hello World", however "Hello world" contains the empty string).
So the following returns false:
Console.WriteLine(string.Empty.Contains("Hello World"));
Whilst this returns true:
Console.WriteLine("Hello World".Contains(string.Empty));
Anyway what you want to check is if the empty string IS contained in any other one:
var retVal = myString.Contains(string.empty);
Which should return true.
Furthermore myString.Contains(null) leads to ArgumentNullException
On the other side null.Contains(aString) leads to the NRE.
the new compilier allows you to do it with the condition check simplified.
string s = null;
Console.WriteLine(s?.Contains("Hello World!"));
It sounds like this question is more about the difference between value types (which cannot be null) and reference types (which can be). In C# and other OO languages it's to do with memory handling.
The value types listed in your MSDN article are all of a known size - e.g. int will always be 32 bits in size etc. Under the hood, these are all structs. As they are of fixed size regardless of the value, C# stores them on the call stack. As null by definition doesn't refer to anything, it has no size. It doesn't make sense for something that exists with a fixed size to also exist with no size.
If you read the documentation for string on MSDN a little closer, you'll see the string is a class not a struct. This is because a string can be of any length you like, so it has to be stored as a pointer to some data on the heap. When you declare a reference type variable, it creates a pointer on the stack to a location on the heap, but there won't be anything at that address until you give that variable a value. Until then, the pointer for that variable is pointing and memory containing literally nothing - i.e. null and it doesn't make sense to try to find "Hello World!" in nothing. An empty string is still a string, but null is literally nothing.
This is probably more detail than you were expecting, but it's good to have an appreciation of the underlying principles of a language, even if you don't need them day to day. This article is well worth a read if you want to go a little more in depth. The idea of null can be a weird concept to get your head around, but once you get the hang of it, it all makes sense, honest!

Exception's ToString() method

I found in someones code following :
catch (Exception exception)
{
Console.WriteLine(exception.ToString());
}
Resharper is graying out the ToString() call which is as always a great suggestion.
How does this C# code work without it ? Will ToString() be called implicitly ?
Console.WriteLine has an overload that takes an object. This object's ToString method is called internally so there's no need for you to add ToString in the first place.
If the exception is being used within a string... For example "something" + exception.ToString() or String.Format("... {0}", exception), then yes, ToString will be called without you having to call it explicitly.
And... as you updated your example, calling Console.WriteLine() against any object value, ToString will be called. Here's the documentation, with as much detail as you could possibly want.
I assume the something is string concatenation or used as a parameter in a formatted string, then yes, ToString is called implicitly.
UPDATE FOLLOWING QUESTION UPDATE
Console has an overload of WriteLine that accepts an object argument, in this version on the method ToString is called if the passed instance is not null - R# is aware of this and suggests the choice of the preferable overload.

Why is it Valid to Concatenate Null Strings but not to Call "null.ToString()"?

This is valid C# code
var bob = "abc" + null + null + null + "123"; // abc123
This is not valid C# code
var wtf = null.ToString(); // compiler error
Why is the first statement valid?
The reason for first one working:
From MSDN:
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.
More information on the + binary operator:
The binary + operator performs string concatenation when one or both operands are of type string.
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 reason of the error in second is:
null (C# Reference) - The null keyword is a literal that represents a null reference, one that does not refer to any object. null is the default value of reference-type variables.
Because the + operator in C# internally translates to String.Concat, which is a static method. And this method happens to treat null like an empty string. If you look at the source of String.Concat in Reflector, you'll see it:
// while looping through the parameters
strArray[i] = (str == null) ? Empty : str;
// then concatenate that string array
(MSDN mentions it, too: http://msdn.microsoft.com/en-us/library/k9c94ey1.aspx)
On the other hand, ToString() is an instance method, which you cannot call on null (what type should be used for null?).
The first sample will be translated into:
var bob = String.Concat("abc123", null, null, null, "abs123");
The Concat method checks input and translate null as an empty string
The second sample will be translated into:
var wtf = ((object)null).ToString();
So a null reference exception will be generated here
The first part of your code is just treated like that in String.Concat,
which is what the C# compiler calls when you add strings. "abc" + null gets translated to String.Concat("abc", null),
and internally, that method replaces null with String.Empty. So, that's why your first part of code does not throw any exception. it is just like
var bob = "abc" + string.Empty + string.Empty + string.Empty + "123"; //abc123
And in 2nd part of your code throws exception because 'null' is not an object, the null keyword is a literal that represents a null reference, one that does not refer to any object. null is the default value of reference-type variables.
And 'ToString()' is a method that can be called by an instance of an object but not any literal.
In the COM framework which preceded .net, it was necessary for any routine which received a string to free it when it was done with it. Because it was very common for empty strings to be passed into and out of routines, and because attempting to "free" a null pointer was defined as a legitimate do-nothing operation, Microsoft decided to have a null string pointer represent an empty string.
To allow for some compatibility with COM, many routines in .net will interpret a null object as a legal representation as an empty string. With a couple of slight changes .net and its languages (most notably allowing instance members to indicate "do not invoke as virtual"), Microsoft could have made null objects of declared type String behave even more like empty strings. If Microsoft had done that, it would have also had to make Nullable<T> work somewhat differently (so as to allow Nullable<String>--something they should IMHO have done anyway) and/or define a NullableString type which would be mostly interchangeable with String, but which would not regard a null as a valid empty string.
As it is, there are some contexts in which a null will be regarded as a legitimate empty string and others in which it won't. Not a terribly helpful situation, but one which programmers should be aware of. In general, expressions of the form stringValue.someMember will fail if stringValue is null, but most framework methods and operators which accept strings as parameters will regard null as an empty string.
'+' is an infix operator. Like any operator it is really calling a method. You could imagine a the non-infix version "wow".Plus(null) == "wow"
The implementer has decided on something like this...
class String
{
...
String Plus(ending)
{
if(ending == null) return this;
...
}
}
So.. your example becomes
var bob = "abc".Plus(null).Plus(null).Plus(null).Plus("123"); // abc123
which is the same as
var bob = "abc".Plus("123"); // abc123
At no point does null become a string. So null.ToString() is no different that null.VoteMyAnswer(). ;)
I guess because it's a literal which doesn't refer to any object. ToString() needs an object.
Adding null to a string is simply ignored. null (in your second example) isn't an instance of any object, so it doesn't even have a ToString() method. It's just a literal.
Someone said in this discussion thread that you can't make a string out of nothing.
(which is a nice phrase as I think). But yes - you can :-), as the following example shows:
var x = null + (string)null;
var wtf = x.ToString();
works fine and does not throw an exception at all. The only difference is that you need to cast one of the nulls into a string - if you remove the (string) cast, then the example still compiles, but throws a run-time exception: "Operator '+' is ambiguous on operands of type '<null>' and '<null>'".
N.B. In the code example above, the value of x is not null as you might expect, it is actually an empty string after you have casted one of the operands into a string.
Slightly different is var a = ((string)null).ToString(); - which compiles but will throw a NullReferenceException. In this case the exception is thrown because the . operator isn't allowed on null values. Using ?. would work here (but ToString isn't executed in this case). The compiler will correctly "create" the variable a as a string.
Another interesting fact is that in C# / .NET the way null is treated is not always the same if you regard different data types. For example:
int? x = 1; // string x = "1";
x = x + null + null;
Console.WriteLine((x==null) ? "<null>" : x.ToString());
Regard the 1st line of the code snippet: If x is a nullable integer variable (i.e. int?) containing value 1, then you're getting the result <null> back. If it is a string (as shown in the comment) with value "1", then you're getting "1" back rather than <null>.
N.B. Also interesting: If you're using var x = 1; for the first line, then you're getting a runtime error. Why? Because the assignment will turn the variable x into the datatype int, which is not nullable. The compiler does not assume int? here, and hence fails in the 2nd line where null is added.
Because there is no difference between string.Empty and null when you concat strings.
You can pass null into string.Format as well. But you are trying to call a method on null, which would always result in a NullReferenceException and therefore generates a compiler error.
If for some reason you really want to do it, you could write an extension method, that checks for null and then returns string.Empty. But an extension like that should only be used when absolutly necessary (in my opinion).
As general: It may or may not valid accepting null as a parameter depending on specification, but it is always invalid to call a method on null.
That's and other topic why the + operator's operands can be null in case of strings. This is kinda VB thing (sorry guys) to make programmers life easier, or supposing the programmer can not deal with nulls. I completely disagree this specification. 'unknown' + 'anything' should be still 'unknown'...

What's the "right" way to convert data from one type to another?

I'm curious as to what the "right" way to convert builtin types is in .NET. Currently i use Convert.To[type]([variable]) without any null checking or anything. What is the best way to do this?
Many types have a TryParse method that you could use. For example:
string input = null;
bool result;
Boolean.TryParse(input, out result);
// result ...
The above is valid and won't throw an exception when the input to parse is null.
When it comes to converting items to a string, you can almost always rely on calling the ToString() method on the object. However, calling it on a null object will throw an exception.
StringBuilder sb = new StringBuilder();
Console.WriteLine(sb.ToString()); // valid, returns String.Empty
StringBuilder sb = null;
Console.WriteLine(sb.ToString()); // invalid, throws a NullReferenceException
One exception is calling ToString() on a nullable type, which would also return String.Empty.
int? x = null;
Console.WriteLine(x.ToString()); // no exception thrown
Thus, be careful when calling ToString; depending on the object, you may have to check for null explicitly.
See this link.
For the most part, casting says "This
object of type A is really an object
of type B-derived-from-A"
Convert.To*() functions say This
object isn't a type B, but there
exists a way to convert to type B"
Some types such as int (Int32) have a TryParse method.
If such a method exists, I try to use that.
Otherwise, I do a null check then pretty much Convert.To as you outlined.
Not sure if there is a "right" way, like most tasks it is contextual.
Kindness,
Dan
It depends on the situation. My best advice would be to study up and become familiar, so you can make better choices on your own, but you should probably start by looking into the following
System.Int32.TryParse()
(there are equivalents for most base types)
DateTime.ParseExact()

Why is there an overload for String.Concat() which accepts one parameter in .NET

Noticed this today when a patch was submitted with the following line:
lblCompletionTime.Text = String.Concat(trainingSkill.EndTime.ToLocalTime())
I can understand why the contributor used that syntax as above line concatenated two strings to form a multi-part date/time string.
Is there some hidden reason for having a single parameter overload of String.Concat() or was it included for "completeness" by the language designers.
I have replaced the line with:
lblCompletionTime.Text = trainingSkill.EndTime.ToLocalTime().ToString(CultureInfo.CurrentCulture)
Which has the same output.
String.Concat(Object) gives you String.Empty when you pass null; ToString would crash with a null pointer exception.
I agree that it doesn't make much sense especially considering the fact that this is the implementation:
public static string Concat(object arg0)
{
if (arg0 == null)
{
return Empty;
}
return arg0.ToString();
}
But it does validate that the argument isn't null so I guess that is something. Still you aren't concatenating anything so I think that this method could have been called
String.ToStringSafe(Object obj) { }
or something similar to better express what the function actually does.
According to MSDN, String.Concat(object)
Creates the String representation of a
specified object.
By looking at the documentation of String.Concat(object), the only advantage I see is that it accepts a null and returns an empty string, which can be an advantage when compared with object.ToString() which would throw a NullReferenceException.
In your example it doesn't help because if trainingSkill.EndTime is null the program will break when invoking ToLocalTime.
I preffer your correction, but I think there's no need for passing CultureInfo.CurrentCulture as a parameter since it is the default behaviour of DateTime.ToString()
In C# it may have little value (aside from the automatic empty string for a null value).
In .Net in general, I could this method signature being very useful in a functional language.
Using String.Concat(Object) to convert an object to a string is the behavior that overload of the function was designed for.
String.Concat Method (Object)
Creates the String representation of a specified object.

Categories