Code Quiz: That Empty Feeling
Which would you use to test if a string is blank? And why? 1. x.Equals(string.Empty)
2. x = ""
3. x.Length = 0
4. x = string.Empty
5. string.Empty.Equals(x)
'Dave Entwistle' on Wed, 18 Oct 2006 06:02:38 GMT, sez: Well, I mostly use sth like
if((null != x)&&(0 != x.Trim().Length))
{
// not empty...
}
else
{
// empty...
}
Why? My therapist mentions C++ influences (logical expressions gave me away), and the paranoid fear that ("" == x) won't catch " ", " " etc.
Didnt't try that new String.IsNullOrEmpty thingy, might be the best solution...
'Doogal' on Wed, 18 Oct 2006 06:03:10 GMT, sez: FxCop tells me I should use
x.Length == 0
cos it's faster, don't know why it is though...
'Dave Entwistle' on Wed, 18 Oct 2006 06:04:50 GMT, sez: HTML not allowed for comments, and multiple spaces get normalized to one? There goes my code formatting... Oh, well. Sorry about the unreadable code.
'Rockgod' on Wed, 18 Oct 2006 06:05:07 GMT, sez: I would go with the option 1. Because 'x' is a reference to a string and 'Equals()' method is the right way to compare with any string to avoid the comparision of memory location instead of string. Instead of 'hard-coding' the empty string "", I'd prefer to use the constant 'string.Empty' so that any changes to the concept of empty string by M$ wouldn't bother me.
'Scott Hanselman' on Wed, 18 Oct 2006 06:23:48 GMT, sez: I use String.IsNullOrEmpty(). I haven't the time or patience to try to optimized managed code with parlor tricks or rememberences of C++ days gone by. That's what I pay the JIT for. The presumption being that the JIT will improve faster than I can.
'Ian Horwill' on Wed, 18 Oct 2006 06:46:16 GMT, sez: x = "" (assuming VB.NET). It's short, expressive, and .NET interns all the ""s into one.
'Dave Entwistle' on Wed, 18 Oct 2006 06:47:20 GMT, sez: Yup, String.IsNullOrEmpty() seems great. The reason I don't use it: our main app is still .Net 1.1 :(
On a side note, I wouldn't call what I use exactly "optimized" - String.Trim() kind of... "de-optimizes" things. But it's good enough for me.
'Ian Horwill' on Wed, 18 Oct 2006 06:47:26 GMT, sez: Oh, yeah, and all the testing for null and trimming is sloppy. Null <> empty string, and you should trim at point of input if that's what you want to do.
'Skup' on Wed, 18 Oct 2006 06:59:12 GMT, sez: In .net 2, string.Equals first check both pointers to see if one is null while the other is not. Not really usefull with not null strings... then it calls string.EqualsHelper private static method.
This method dereference both string to get their length and compare it.
So x.Equals(string.Empty), x == "", x == string.Empty and string.Empty.Equals() will need to dereference both x string and Empty string to get their length.
Dereferencing string.Empty to get its length is quite useless since it's always 0...
string.IsNullOrEmpty just make one reference comparison to null and one derefencement to get length and compare it to zero...
You can just test x.Length == 0 if you're sure that x is not null.
The best reason is also that is easier to read.
'Dave Entwistle' on Wed, 18 Oct 2006 07:11:07 GMT, sez: Seems we need to define "empty" and "blank" :)
Is "" empty? is " " empty? is " " empty? or blank?
What I actually want to know when I use one of these checks is: is this string *USABLE* in this context?
'Dave Entwistle' on Wed, 18 Oct 2006 07:11:57 GMT, sez: P.S. change " " with a whitespace :)
'Rik Hemsley' on Wed, 18 Oct 2006 07:12:52 GMT, sez: If trimming an already-probably-empty string is enough of an inefficiency to cause a measurable performance impact, you'll notice that when you are at the optimisation stage and it'll be easy to spot and fix.
Having said that, your unit tests should spot when you pass a null string (usually by accident, I'd guess), so, assuming your tests are sound, you can just compare to "" - for the reasons given by Ian.
Personally, I prefer:
enum SuperBool { True, False, FileNotFound }
if (String.Empty.Length > 0) { Thread.Abort(); }
if (String.Empty.Length < 0) { return SuperBool.FileNotFound; }
return (x.Length != String.Empty.Length) != True;
'Paul Stovell' on Wed, 18 Oct 2006 07:16:50 GMT, sez: What's with the single =? Real men use == (C#) :)
I use:
x == string.Empty
or:
x == ""
For no reason other than it "reads" better - that is your brain processes it faster. If performance is so important to you that you need to optimise empty string comparrisons, you shouldn't be using .NET.
'Christoph Richter' on Wed, 18 Oct 2006 07:19:41 GMT, sez: I use x.Length == 0 because here it dont has to compare the value with anything and so dont need to touch the memory. if it could be null, the string.IsNullOrEmpty is the best. equal would be to check first, of its null and then compare the length to 0.
all others refer to the string.empty and then the clr has first to intern your string and compare if the reference to the string.empty are equal.
'Geoff Appleby' on Wed, 18 Oct 2006 07:20:55 GMT, sez: Well, I'm presuming out of your 5 samples that they're in c# (lower case 's' at the start of the word 'string'.
Therefore, unmbers 2, 3 and 4 are all knocked out because with only one '=' they're doinf an assignment, not a test.
Out of 1 and 5, I'd take 5, since if x is null you could get a NullReferenceException in 1.
Me, I always like doing 'If x = Nothing Then' since it checks for both null and empty :)
'Eric D, Burdo' on Wed, 18 Oct 2006 11:11:03 GMT, sez: In .Net 1.1, the best approach is to use .Length. Now that assumes your string is not null. If so, .Length will trigger an exception.
In 2.0, use the IsNullOrEmpty.
Just comparing against "" is slow. Same reason you shouldn't do string comparisons with the = sign. They are slow.
'Casey Barton' on Wed, 18 Oct 2006 11:25:05 GMT, sez: Here is my simple comparison of these 5 examples, plus isNullOrEmpty. Typical results on my machine:
1) 0.905114203607809
2) 0.929754939818849
3) 0.0515111724844246
4) 0.926342983740142
5) 0.896933589296168
6) 0.25979684523918
The only thing that surprised me was how much slower IsNullOrEmpty was than the .Length test. I guess checking for null is hard. :)
---
using System;
using System.Runtime.InteropServices;
public class MyClass
{
[DllImport("Kernel32.dll")]
private static extern bool QueryPerformanceCounter(out long lpPerformanceCount);
[DllImport("Kernel32.dll")]
private static extern bool QueryPerformanceFrequency(out long lpFrequency);
public static void Main()
{
long freq, start, end;
const int count = 100000000;
string foo = "foo";
QueryPerformanceFrequency(out freq);
double dfreq = (double)freq;
QueryPerformanceCounter(out start);
for (int i = 0; i < count; i++) if (foo.Equals(string.Empty));
QueryPerformanceCounter(out end);
Console.WriteLine(end / dfreq - start / dfreq);
QueryPerformanceCounter(out start);
for (int i = 0; i < count; i++) if (foo == "");
QueryPerformanceCounter(out end);
Console.WriteLine(end / dfreq - start / dfreq);
QueryPerformanceCounter(out start);
for (int i = 0; i < count; i++) if (foo.Length == 0);
QueryPerformanceCounter(out end);
Console.WriteLine(end / dfreq - start / dfreq);
QueryPerformanceCounter(out start);
for (int i = 0; i < count; i++) if (foo == string.Empty);
QueryPerformanceCounter(out end);
Console.WriteLine(end / dfreq - start / dfreq);
QueryPerformanceCounter(out start);
for (int i = 0; i < count; i++) if (string.Empty.Equals(foo));
QueryPerformanceCounter(out end);
Console.WriteLine(end / dfreq - start / dfreq);
QueryPerformanceCounter(out start);
for (int i = 0; i < count; i++) if (string.IsNullOrEmpty(foo));
QueryPerformanceCounter(out end);
Console.WriteLine(end / dfreq - start / dfreq);
Console.ReadLine();
}
}
'Wesley Shephard' on Wed, 18 Oct 2006 13:17:05 GMT, sez: String.IsNullOrEmpty() is the only way to fly in 2.0. We have a small utility function that performs the same operation in 1.1 (from memory):
StringUtil.IsNullOrEmpty(string str)
{
if (str == null) return true;
if (str.Length == 0) return true;
return false;
}
Simple enough really.
'Greg Robinson' on Wed, 18 Oct 2006 15:00:40 GMT, sez: V 1.1 this has stood the test of time for us:
Public Function StringIsEmpty(ByVal value As String) As Boolean
Return value Is Nothing OrElse value.Trim().Length = 0
End Function ' StringIsEmpty
'' on Wed, 18 Oct 2006 16:41:52 GMT, sez: string x = "whatever";
string y = "something else"; //or string.Empty
bool ignoreCase = true; //or false, your call
CultureInfo culture = CultureInfo.InvariantCulture; //or some other culture, again your call.
if ( 0 == string.Compare( x, y, ignoreCase, culture ) )
{
//wa-wa-wee-wa
}
'mhall@just3ws.com' on Wed, 18 Oct 2006 16:49:43 GMT, sez: Hi, I forgot to take the blame for string.Compare( ... ).
For better or worse.
:-)
'Aaron Bull' on Wed, 18 Oct 2006 20:37:22 GMT, sez: Watch out for the String.IsNullOrEmpty bug.
http://connect.microsoft.com/VisualStudio/feedback/ViewFeedback.aspx?FeedbackID=113102
Cheers,
Aaron
'Matthew' on Wed, 18 Oct 2006 21:40:52 GMT, sez: x = string.Empty
'lb' on Wed, 18 Oct 2006 22:10:49 GMT, sez: @geoff appleby:
actually these samples are in VB.net. The lowercase s in string was a typo -- but not a compile problem, since vb is case-insensitive. So the = is comparison, not assignment... probably.
i prefer string.Empty (and string.IsNullOrEmpty) but i'd forgotten why, and just wanted to throw the question out there to get some responses. Most of the blog entries i read on the topic were inadequate and didn't consider the null case, which is the clincher i think.
'Dan F' on Wed, 18 Oct 2006 22:40:27 GMT, sez: As a vb user from waaaay back, I'd probably use len(s) = 0. Really gotta try and get into the habit of String.IsNullOrEmpty, its more verbose but looks better. I wouldn't mind an overload called HasValue so it looks the same as the Nullable types :)
'lb' on Wed, 18 Oct 2006 22:58:08 GMT, sez: @DanF:
>I wouldn't mind an overload called
>HasValue so it looks the same as the
>Nullable types :)
while i could happily sit here and pick holes in that idea (e.g. strings are not value types so they never really have a value) -- i think you're onto something there.
i was listening to Jeff Snover talk about powershell and about consistency of interfaces being important in 'management solutions' -- and yeh, that makes me lean toward liking your idea here.
'Jon' on Wed, 29 Nov 2006 18:38:49 GMT, sez: Assuming string is not null (you would have to test for it), they all do the same thing, but number 3 is slightly faster under high iterations.
In a 10 million iteration test, these are the results (in milliseconds) for tests 1 through 5
93,110,265,266,46
Try this code out and see for yourself:
{
string test = "test";
int j = 0;
long test1time = 0;
long test2time = 0;
long test3time = 0;
long test4time = 0;
long test5time = 0;
long starttime = Environment.TickCount;
//Test 1 Equals string.Empty
for (int i = 0; i < 10000000; i++)
{
if (test.Equals(string.Empty))
{
j++;
}
}
test1time = Environment.TickCount - starttime;
//Test 2 Equals ""
starttime = Environment.TickCount;
for (int i = 0; i < 10000000; i++)
{
if (test.Equals(""))
{
j++;
}
}
test2time = Environment.TickCount - starttime;
//Test 3 ""
starttime = Environment.TickCount;
for (int i = 0; i < 10000000; i++)
{
if (test == "")
{
j++;
}
}
test3time = Environment.TickCount - starttime;
//Test 4 string.empty
starttime = Environment.TickCount;
for (int i = 0; i < 10000000; i++)
{
if (test == string.Empty)
{
j++;
}
}
test4time = Environment.TickCount - starttime;
//Test 5 string.length
starttime = Environment.TickCount;
for (int i = 0; i < 10000000; i++)
{
if (test.Length == 0)
{
j++;
}
}
test5time = Environment.TickCount - starttime;
//Sjow Results
string msg = "Test run times (ms) -> Test1,Test2,Test3,Test4,Test5: " + test1time.ToString() + "," + test2time.ToString() + "," + test3time.ToString() + "," + test4time.ToString() + "," + test5time.ToString();
MessageBox.Show(msg);
}
|