ILSpy shows that String.IsNullOrEmpty
is implemented in terms of String.Length
. But then why is String.IsNullOrEmpty(s)
faster than
it may be caused by the types of the involved variables. *Empty seems to use a boolean, length an int (i guess).
Peace !
You test is wrong somethere. IsNullOrEmpty can't be faster by definition, since it makes additional null comparison operation, and then tests the Length.
So the answer can be: it's faster because of your test. However even your code shows that IsNullOrEmpty is consistently slower on my machine in both x86 and x64 modes.
I believe your test is not correct:
This test shows that string.IsNullOrEmpty
is always slower than s.Length==0
because it performs an additional null check:
var strings = "A,B,,C,DE,F,,G,H,,,,I,J,,K,L,MN,OP,Q,R,STU,V,W,X,Y,Z,".Split(',');
var testers = new Func<string, bool>[] {
s => s == String.Empty,
s => s.Length == 0,
s => String.IsNullOrEmpty(s),
s => s == "" ,
};
int n = testers.Length;
var stopwatches = Enumerable.Range(0, testers.Length).Select(_ => new Stopwatch()).ToArray();
int count = 0;
for(int i = 0; i < n; ++i) { // iterate testers one by one
Stopwatch sw = stopwatches[i];
var tester = testers[i];
sw.Start();
for(int j = 0; j < 10000000; ++j) // increase this count for better precision
count += strings.Count(tester);
sw.Stop();
}
for(int i = 0; i < testers.Length; i++)
Console.WriteLine(stopwatches[i].ElapsedMilliseconds);
Results:
6573
5328
5488
6419
You can use s.Length==0
when you are ensure that target data does not contains null strings. In other cases I suggest you use the String.IsNullOrEmpty
.
I think it is impossible IsNullOrEmpty
to be faster because as all the rest said it also makes a check for null. But faster or not the difference is going to be so small, that this gives a plus on using IsNullOrEmpty
just because of this additional null check that makes your code safer.
It's because you ran your benchmark from within Visual Studio which prevents JIT compiler from optimizing code. Without optimizations, this code is produced for String.IsNullOrEmpty
00000000 push ebp
00000001 mov ebp,esp
00000003 sub esp,8
00000006 mov dword ptr [ebp-8],ecx
00000009 cmp dword ptr ds:[00153144h],0
00000010 je 00000017
00000012 call 64D85BDF
00000017 mov ecx,dword ptr [ebp-8]
0000001a call 63EF7C0C
0000001f mov dword ptr [ebp-4],eax
00000022 movzx eax,byte ptr [ebp-4]
00000026 mov esp,ebp
00000028 pop ebp
00000029 ret
and now compare it to code produced for Length == 0
00000000 push ebp
00000001 mov ebp,esp
00000003 sub esp,8
00000006 mov dword ptr [ebp-8],ecx
00000009 cmp dword ptr ds:[001E3144h],0
00000010 je 00000017
00000012 call 64C95BDF
00000017 mov ecx,dword ptr [ebp-8]
0000001a cmp dword ptr [ecx],ecx
0000001c call 64EAA65B
00000021 mov dword ptr [ebp-4],eax
00000024 cmp dword ptr [ebp-4],0
00000028 sete al
0000002b movzx eax,al
0000002e mov esp,ebp
00000030 pop ebp
00000031 ret
You can see, that code for Length == 0 does everything that does code for String.IsNullOrEmpty, but additionally it tries something like foolishly convert boolean value (returned from length comparison) again to boolean and this makes it slower than String.IsNullOrEmpty.
If you compile program with optimizations enabled (Release mode) and run .exe file directly from Windows, code generated by JIT compiler is much better. For String.IsNullOrEmpty it is:
001f0650 push ebp
001f0651 mov ebp,esp
001f0653 test ecx,ecx
001f0655 je 001f0663
001f0657 cmp dword ptr [ecx+4],0
001f065b sete al
001f065e movzx eax,al
001f0661 jmp 001f0668
001f0663 mov eax,1
001f0668 and eax,0FFh
001f066d pop ebp
001f066e ret
and for Length == 0:
001406f0 cmp dword ptr [ecx+4],0
001406f4 sete al
001406f7 movzx eax,al
001406fa ret
With this code, result are as expected, i.e. Length == 0 is slightly faster than String.IsNullOrEmpty.
It's also worth mentioning, that using Linq, lambda expressions and computing modulo in your benchmark is not such a good idea, because these operations are slow (relatively to string comparison) and make result of benchmark inaccurate.
Your benchmark does not measure String.IsNullOrEmpty vs String.Length, but rather how different lambda expressions are generated to functions. I.e. it is not very surprising that delegate that just contains single function call (IsNullOrEmpty) is faster than one with function call and comparison (Length == 0).
To get comparison of actuall call - write code that calls them directly without delegates.
EDIT: My rough measurements show that delegate version with IsNullOrEmpty is slightly faster then the rest, while direct calls to the same comparision are in reverse order (and about twice faster due to significantly less number of extra code) on my machine. Results likely to wary between machines, x86/x64 mode, as well between versions of runtime. For practical purposes I would consider all 4 ways are about the same if you need to use them in LINQ queries.
Overall I doubt there will be measurable difference in real program cased by choice between these methods, so pick the one that is most readable to you and use it. I generally prefer IsNullOrEmpty since it gives less chance to get ==/!= wrong in a condition.
Removal of string manipulation altogether from time critical code will likley bring much higer benifit that picking between these choices, also dropping LINQ for critical code is an option. As always - make sure to measure overall program speed in real life scenario.