A revisit to a tiny C# shortcut

My blog on string.IsNullOrEmpty() caused quite a stir (in my micro-scale, anyway), I got a number of comments, most of them interesting, and I feel happy of *not* being the only guy interested in silly small details. The feedback forced me to polish my benchmark, first of all James Bogosian is right: the performance differences are really small, I had to do 20'000.000 and 30'000.000 comparisons to see some stable differences. I also introduced the name.Length > 0 comparison out of several suggestions; after some cleaning, the results for the not null and not empty string tests were these:

.Length > 0 80 ms
string.IsNullOrEmpty() 110 ms
!= "" 270 ms
!= string.Empty 440 ms

And, surprise Edgar, name.Length > 0 is the best so Ramon Smits and other guys get a point here. The other  unexpected result is that comparing to string.Empty is a real bummer, so Darren Kopp suggestion is not really good (but he also supported the use of the Length property, so you're just OK, Darren). Someone suggested that comparing with "" is bad because a lot of string objects are generated, Ildasm shows that a ldstr "" instruction is generated just before the comparison, and although I'm far from an IL expert, I suspect no extra strings are being instantiated. Personally, I will stick to string.IsNullOrEmpty() because, as James pointed out, it's not only a matter of performance but of readability (or perhaps I am just rationalizing my bad habits ;-) ). You can download the test class from here, try it, mangle it, feedback me.

15 Comments

  • I must say, the people that worked on the IL did a hell of a job.

  • Oh, do you have numbers for memory usage for each test?

  • If you compare with null (what is missing in the first test with .Length) you will have the same result as string.IsNullOrEmpty(). Have a look on that static method you will find this:



    public static bool IsNullOrEmpty(string value)

    {

    if (value != null)

    {

    return (value.Length == 0);

    }

    return true;

    }



    CIAO

    Michael

  • The person who commented that comparing with "" generates a lot of string objects is wrong.



    The String class has a so-called "intern pool" with one copy of each unique literal constant in a program. Each time you reference a literal including the literal "" for an empty string, you get back a reference to the *same* object from the intern pool.

  • Michael: He! That's a good one, so the extra time I see in my benchmark is probably due to the method call overhead. May be in a future version the compiler will inline the code and then we'll have both performance and readability. Come to think of it, may be there's already a compiler switch to do this, any takers?

  • Joe,



    good to know. I was simply speculating on whether comparing to "" was good or bad.

  • Joe, notice that my comment about the "" creating a new string object had a question mark behind it, because I was only posing a hypothesis as to the slow down.



    Edward,

    I ran all of your code, and of course made some tweaks of my own. This is what i found out. I found that your findings were the same as mine, including my own code. As I began testing more, i did not bother with != "" or != string.Empty comparisons as they did not perform well at all.



    The best performing condition is the following:



    if (s != null && s.Length == 0)



    which is basically just a rewrite of the isNullOrEmpty method, as michael stated (thank goodness for the reflector). here is the code i used to test it



    start = DateTime.Now;

    for (int l = 0; l < 10000000; l++)

    {

    switch (l % 3)

    {

    case 0:

    isValid2 = (e != null && e.Length > 0);

    break;

    case 1:

    isValid1 = (n != null && n.Length > 0);

    break;

    case 2:

    isValid3 = (f != null && f.Length > 0);

    break;

    default:

    break;

    }

    }

    finish = DateTime.Now;

    lapse = finish - start;



    where e is "", n is null, and f is "Hello World!". I used the case on all other tests as well, to test variations (though predictable) of null, empty, or normal strings. This, I feel, will give a more rounded response time as some strings, like the null, will return much quicker than non-null strings.



    I noticed that there was no difference between using .Length == 0 and .Length > 0, which isn't really surprising, but still worth testing.



    In final, the statement i posted above consistently about 100 ms faster than calling the IsNullOrEmpty method, due to the overhead of calling a method (not to mention calling a method within a loop).



    All in all, I agree that IsNullOrEmpty is the most readable and elegant, but if extreme performance is a requirement, then you may want to use the statement listed above.



    Also worth mentioning is that I did rewrite the IsNullOrEmpty method's code within my own class, and tested that, and the results were identical with calling that one or string.IsNullOrEmpty.

  • Correct me if I am wrong but you have to see if the string is null before trying to see the Length. If you try to get the Length of a null string you get an error.

  • Wow, this is good info. I've been comparing using String.Empty in a lot of my code and I'm surprised it's slowest. In 2.0 I've been in the IsNullOrEmpty. Good info.

  • John, I wouldn't worry. Edgar had to run the tests 20-30 _million_ times to see appreciable differences (if you can call 440ms versus 80 ms "appreciable")

  • Were all the performance tests run with an app compiled in Release mode?

  • Joe: Yes, I used release mode for all my tests.

  • I ran my tests in release mode as well. Debug mode results were fairly consistent to release mode, but took about 200 ms longer.

  • 441716.. Corking :)

  • Насчет тонкого юмора поняли... А бывает толстый юмор?
    интерактивные картинки ребенок

Comments have been disabled for this content.