How to do ToString for a possibly null object?

2019-01-10 18:45发布

问题:

Is there a simple way of doing the following:

String s = myObj == null ? "" : myObj.ToString();

I know I can do the following, but I really consider it as a hack:

String s = "" + myObj;

It would be great if Convert.ToString() had a proper overload for this.

回答1:

C# 6.0 Edit:

With C# 6.0 we can now have a succinct, cast-free version of the orignal method:

string s = myObj?.ToString() ?? "";

Or even:

string s = $"{myObj}";

Original Answer:

String s = (myObj ?? String.Empty).ToString();

or

String s = (myObjc ?? "").ToString()

to be even more concise.

Unfortunately, as has been pointed out you'll often need a cast on either side to make this work with non String or Object types:

String s = (myObjc ?? (Object)"").ToString()
String s = ((Object)myObjc ?? "").ToString()

Therefore, while it maybe appears elegant, the cast is almost always necessary and is not that succinct in practice.

As suggested elsewhere, I recommend maybe using an extension method to make this cleaner:

public static string ToStringNullSafe(this object value)
{
    return (value ?? string.Empty).ToString();
}


回答2:

string.Format("{0}", myObj);

string.Format will format null as an empty string and call ToString() on non-null objects. As I understand it, this is what you were looking for.



回答3:

With an extension method, you can accomplish this:

public static class Extension
{
    public static string ToStringOrEmpty(this Object value)
    {
        return value == null ? "" : value.ToString();
    }
}

The following would write nothing to the screen and would not thrown an exception:

        string value = null;

        Console.WriteLine(value.ToStringOrEmpty());


回答4:

It would be great if Convert.ToString() had a proper overload for this.

There's been a Convert.ToString(Object value) since .Net 2.0 (approx. 5 years before this Q was asked), which appears to do exactly what you want:

http://msdn.microsoft.com/en-us/library/astxcyeh(v=vs.80).aspx

Am I missing/misinterpreting something really obvious here?



回答5:

I disagree with that this:

String s = myObj == null ? "" : myObj.ToString();

is a hack in any way. I think it's a good example of clear code. It's absolutely obvious what you want to achieve and that you're expecting null.

UPDATE:

I see now that you were not saying that this was a hack. But it's implied in the question that you think this way is not the way to go. In my mind it's definitely the clearest solution.



回答6:

string s = String.Concat(myObj);

would be the shortest way I guess and also have neglible performance overhead. Keep in mind though it wouldn't be quite clear for the reader of the code what the intention is.



回答7:

actually I didnt understand what do you want to do. As I understand, you can write this code another way like this. Are you asking this or not? Can you explain more?

string s = string.Empty;
    if(!string.IsNullOrEmpty(myObj))
    {
    s = myObj.ToString();
    }


回答8:

I might get beat up for my answer but here goes anyway:

I would simply write

string s = "" if (myObj != null) { x = myObj.toString(); }

Is there a payoff in terms of performance for using the ternary operator? I don't know off the top of my head.

And clearly, as someone above mentioned, you can put this behavior into a method such as safeString(myObj) that allows for reuse.



回答9:

Holstebroe's comment would be your best answer:

string s = string.Format("{0}", myObj);

If myObj is null, Format places an Empty String value there.

It also satisfies your one line requirement and is easy to read.



回答10:

I had the same problem and solved it by simply casting the object to string. This works for null objects too because strings can be nulls. Unless you absolutely don't want to have a null string, this should work just fine:

string myStr = (string)myObj; // string in a object disguise or a null


回答11:

Some (speed) performance tests summarizing the various options, not that it really matters #microoptimization (using a linqpad extension)

Options

void Main()
{
    object objValue = null;
    test(objValue);
    string strValue = null;
    test(strValue);
}

// Define other methods and classes here
void test(string value) {
    new Perf<string> {
        { "coallesce", n => (value ?? string.Empty).ToString() },
        { "nullcheck", n => value == null ? string.Empty : value.ToString() },
        { "str.Format", n => string.Format("{0}", value) },
        { "str.Concat", n => string.Concat(value) },
        { "string +", n => "" + value },
        { "Convert", n => Convert.ToString(value) },
    }.Vs();
}

void test(object value) {
    new Perf<string> {
        { "coallesce", n => (value ?? string.Empty).ToString() },
        { "nullcheck", n => value == null ? string.Empty : value.ToString() },
        { "str.Format", n => string.Format("{0}", value) },
        { "str.Concat", n => string.Concat(value) },
        { "string +", n => "" + value },
        { "Convert", n => Convert.ToString(value) },
    }.Vs();
}

Probably important to point out that Convert.ToString(...) will retain a null string.

Results

Object

  • nullcheck 1.00x 1221 ticks elapsed (0.1221 ms) [in 10K reps, 1.221E-05 ms per]
  • coallesce 1.14x 1387 ticks elapsed (0.1387 ms) [in 10K reps, 1.387E-05 ms per]
  • string + 1.16x 1415 ticks elapsed (0.1415 ms) [in 10K reps, 1.415E-05 ms per]
  • str.Concat 1.16x 1420 ticks elapsed (0.142 ms) [in 10K reps, 1.42E-05 ms per]
  • Convert 1.58x 1931 ticks elapsed (0.1931 ms) [in 10K reps, 1.931E-05 ms per]
  • str.Format 5.45x 6655 ticks elapsed (0.6655 ms) [in 10K reps, 6.655E-05 ms per]

String

  • nullcheck 1.00x 1190 ticks elapsed (0.119 ms) [in 10K reps, 1.19E-05 ms per]
  • Convert 1.01x 1200 ticks elapsed (0.12 ms) [in 10K reps, 1.2E-05 ms per]
  • string + 1.04x 1239 ticks elapsed (0.1239 ms) [in 10K reps, 1.239E-05 ms per]
  • coallesce 1.20x 1423 ticks elapsed (0.1423 ms) [in 10K reps, 1.423E-05 ms per]
  • str.Concat 4.57x 5444 ticks elapsed (0.5444 ms) [in 10K reps, 5.444E-05 ms per]
  • str.Format 5.67x 6750 ticks elapsed (0.675 ms) [in 10K reps, 6.75E-05 ms per]