is operator + object casting or as operator + null comparison?
By ganton ~ June 27th, 2009. Filed under: .Net.
This week I found in the source code of one of our projects that people use “is” operator + object casting in places that they can use “as” operator + null comparison.
1: // "is" operator + object casting
2: if (myObj is MyObject)
3: {
4: MyObject obj = (MyObject)myObj;
5: }
6:
7: // "as" operator + null comparison
8: MyObject obj = myObj as MyObject;
9: if (obj != null)
10: {
11: // do some work with obj
12: }
What is the problem? The problem is that in the first case you cast the object two times which is slower than if you cast the object only one time as in the second case. Why it happens? Because the “is” operator casts the object behind the scene and if the cast is successful it will return true, otherwise false. Consequently, the first case is slower than the second case. You may suggest that nowadays the hardware is very fast and you will be correct but the problem is that most of the developers that use the first case even don’t understand why is better to use the second one. Below is the test sample for the performance that I did. The count is a very high number that will allow us to see the difference.
1: using System;
2: using System.Collections.Generic;
3: using System.Linq;
4: using System.Text;
5: using System.Diagnostics;
6:
7: namespace AsIsTest
8: {
9: class Program
10: {
11:
12: public class MyObject
13: {
14: public MyObject Parent { get; set; }
15: }
16:
17: static void Main(string[] args)
18: {
19: int count = 100000000;
20: object myObj = new MyObject { Parent = new MyObject() };
21: Stopwatch watch = new Stopwatch();
22: watch.Start();
23: for (int i = 0; i < count; i++)
24: {
25: MyObject obj;
26: if (myObj is MyObject)
27: {
28: obj = (MyObject)myObj;
29: }
30: }
31: watch.Stop();
32: Console.WriteLine("is and cast time if true: " + watch.ElapsedMilliseconds);
33:
34: watch.Reset();
35: watch.Start();
36: for (int i = 0; i < count; i++)
37: {
38: MyObject obj = myObj as MyObject;
39: if (obj != null)
40: {
41:
42: }
43: }
44: watch.Stop();
45: Console.WriteLine("as and null comparison time: " + watch.ElapsedMilliseconds);
46:
47: Console.Read();
48:
49: }
50: }
51: }
The result is below.
Note that in the sample above both operators are able to cast the project. In this case there is a performance advantage of the second sample but if the object cannot be casted you will get the similar results for both cases because only one casting takes place in the first sample. Below is a sample when the object can not be casted.
1: watch.Start();
2: for (int i = 0; i < count; i++)
3: {
4: string obj;
5: if (myObj is string)
6: {
7: obj = (string)myObj;
8: }
9: }
10: watch.Stop();
11: Console.WriteLine("is and cast time if true: " + watch.ElapsedMilliseconds);
12:
13: watch.Reset();
14: watch.Start();
15: for (int i = 0; i < count; i++)
16: {
17: string obj = myObj as string;
18: if (obj != null)
19: {
20:
21: }
22: }
23: watch.Stop();
24: Console.WriteLine("as and null comparison time: " + watch.ElapsedMilliseconds);
And the result is below.
It’s funny but on my machine the results are completely the same. I’ve started the application several time and they are the same.
June 29th, 2009 at 1:32 pm
Good post. Interesting result in 2 test. I was think numbers must be also different.