Convert.ToString(null)
returns
null
As I expected.
But
Convert.ToString(null as object)
Following on from JaredPar's excellent overload resolution answer - the question remains "why does Convert.ToString(string)
return null, but Convert.ToString(object)
return string.Empty
"?
And the answer to that is...because the docs say so:
Convert.ToString(string) returns "the specified string instance; no actual conversion is performed."
Convert.ToString(object) returns "the string representation of value, or String.Empty if value is null."
EDIT: As to whether this is a "bug in the spec", "very bad API design", "why was it specified like this", etc. - I'll take a shot at some rationale for why I don't see it as big deal.
System.Convert
has methods for converting every base type to itself. This is strange - since no conversion is needed or possible, so the methods end up just returning the parameter. Convert.ToString(string)
behaves the same. I presume these are here for code generation scenarios.Convert.ToString(object)
has 3 choices when passed null
. Throw, return null, or return string.Empty. Throwing would be bad - doubly so with the assumption these are used for generated code. Returning null requires your caller do a null check - again, not a great choice in generated code. Returning string.Empty seems a reasonable choice. The rest of System.Convert
deals with value types - which have a default value.Convert.ToString(string)
means breaking the "no actual conversion" rule. Since System.Convert
is a static utility class, each method can be logically treated as its own. There's very few real world scenarios where this behavior should be "surprising", so let usability win over (possible) correctness.There are 2 overloads of ToString
that come into play here
Convert.ToString(object o);
Convert.ToString(string s);
The C# compiler essentially tries to pick the most specific overload which will work with the input. A null
value is convertible to any reference type. In this case string
is more specific than object
and hence it will be picked as the winner.
In the null as object
you've solidified the type of the expression as object
. This means it's no longer compatible with the string
overload and the compiler picks the object
overload as it's the only compatible one remaining.
The really hairy details of how this tie breaking works is covered in section 7.4.3 of the C# language spec.