Answered by:
Casting Performance

Question
-
Let's say I have an object that needs to be cast before passing it to two different functions. Is there a performance hit if I cast the object twice, once in each function parameter versus casting it once to a variable and simple passing that variable to the functions?
For example, given object o which would be better:
Function1((T)o); Function2((T)o);
or
T temp = (T)o; Function1(temp); Function2(temp);
I like how compact and concise the first version is but worry that I could be introducing inefficiencies into my code.
Friday, June 24, 2011 2:21 PM
Answers
-
I've compiled a sample program with compiler optimizations and without.
using System; class A { public static int Function(int x) { return x+1; } public static void Main() { object a = 1; Function((int)a); Function((int)a); } }
In both cases unboxing will occur:
.method public hidebysig static void Main() cil managed { .entrypoint // Code size 32 (0x20) .maxstack 1 .locals init (object V_0) IL_0000: ldc.i4.1 IL_0001: box [mscorlib]System.Int32 IL_0006: stloc.0 IL_0007: ldloc.0 IL_0008: unbox.any [mscorlib]System.Int32 IL_000d: call int32 A::Function(int32) IL_0012: pop IL_0013: ldloc.0 IL_0014: unbox.any [mscorlib]System.Int32 IL_0019: call int32 A::Function(int32) IL_001e: pop IL_001f: ret } // end of method A::Main
And with reference types (conversion from object to string) castclass intstruction will be generated:
<strong> IL_0014: castclass [mscorlib]System.String</strong> IL_0019: call void A::Function(string) IL_001e: nop IL_001f: ldloc.0 <strong> IL_0020: castclass [mscorlib]System.String</strong> IL_0025: call void A::Function(string)
If I run this program using different types (and different conversion types boxing, reference type cast, no cast) in loop with 10 000 000 iterations, i'l get following numbers:With unboxing: 9 ms
Function((int)a); Function((int)a);
With conversion from int to long: 9 msFunction((long)a); Function((long)a);With conversion from int to double: 9 ms
Function((double)a); Function((double)a);
With conversion from one reference type to another reference type: 31 ms
Function((string)a); Function((string)a);
With single conversion from one reference type to another reference type: ~15 msstring s = a as string;Function(s);Function(s);With single conversion and null comparison from one reference type to another reference type: ~23 msstring s = a as string;if (s!=null){Function(s);Function(s);}Without conversion, reference type (string): 14 ms:Function(a); Function(a);
Without conversion, value type (int): 9 ms:Function(a); Function(a);
So, in general I would conclude that reference type casting is more expensive than unboxing. But if your loop has relatively small amount of iterations (< 1000000) and if cost of function execution is quite significant you might safelly pick whatever option you like more.
Please remember to mark the replies as answers if they helpSaturday, June 25, 2011 7:24 PM -
Unnecessary casting is a performance warning when you enable static Code Analysis.Casting is expesnive.Another corrollary situation is:
if (variable is MyType) { MyType typedVariable = (MyType)variable; }
This block of code is why the as operator was invented.The correct way to write this is:MyType typedVariable = variable as MyType; if (typedVariable != null) { }
Every programmer prefers the first block - using the is operator and casting - because it reads easier. But it's a double cast and code analysis will warn you about it because casting is very expensive.EvanSunday, June 26, 2011 3:26 AM
All replies
-
Hi,
Here is the nice article on performance analysis of primitive type casting, down casting and up casting...
http://www.codeproject.com/KB/cs/csharpcasts.aspx
If this post answers your question, please click "Mark As Answer". If this post is helpful please click "Mark as Helpful".Friday, June 24, 2011 2:35 PM -
Unless you are doing it in a really, really tight loop you probably won't notice the difference. I think though if you are going to need it twice like that I'd do it once and use the result multiple times. I typically prefer the 'as' cast as the article Kris444 points out mentions and then check for null on failure to cast.
var temp = o as T; if (temp != null) { Function1(temp); Function2(temp); }
James Michael Hare
Blog: http://www.geekswithblogs.net/BlackRabbitCoder
Twitter: @BlkRabbitCoder
There are 10 kinds of people in the world: those who know binary and those who don't...
Friday, June 24, 2011 3:07 PM -
I've compiled a sample program with compiler optimizations and without.
using System; class A { public static int Function(int x) { return x+1; } public static void Main() { object a = 1; Function((int)a); Function((int)a); } }
In both cases unboxing will occur:
.method public hidebysig static void Main() cil managed { .entrypoint // Code size 32 (0x20) .maxstack 1 .locals init (object V_0) IL_0000: ldc.i4.1 IL_0001: box [mscorlib]System.Int32 IL_0006: stloc.0 IL_0007: ldloc.0 IL_0008: unbox.any [mscorlib]System.Int32 IL_000d: call int32 A::Function(int32) IL_0012: pop IL_0013: ldloc.0 IL_0014: unbox.any [mscorlib]System.Int32 IL_0019: call int32 A::Function(int32) IL_001e: pop IL_001f: ret } // end of method A::Main
And with reference types (conversion from object to string) castclass intstruction will be generated:
<strong> IL_0014: castclass [mscorlib]System.String</strong> IL_0019: call void A::Function(string) IL_001e: nop IL_001f: ldloc.0 <strong> IL_0020: castclass [mscorlib]System.String</strong> IL_0025: call void A::Function(string)
If I run this program using different types (and different conversion types boxing, reference type cast, no cast) in loop with 10 000 000 iterations, i'l get following numbers:With unboxing: 9 ms
Function((int)a); Function((int)a);
With conversion from int to long: 9 msFunction((long)a); Function((long)a);With conversion from int to double: 9 ms
Function((double)a); Function((double)a);
With conversion from one reference type to another reference type: 31 ms
Function((string)a); Function((string)a);
With single conversion from one reference type to another reference type: ~15 msstring s = a as string;Function(s);Function(s);With single conversion and null comparison from one reference type to another reference type: ~23 msstring s = a as string;if (s!=null){Function(s);Function(s);}Without conversion, reference type (string): 14 ms:Function(a); Function(a);
Without conversion, value type (int): 9 ms:Function(a); Function(a);
So, in general I would conclude that reference type casting is more expensive than unboxing. But if your loop has relatively small amount of iterations (< 1000000) and if cost of function execution is quite significant you might safelly pick whatever option you like more.
Please remember to mark the replies as answers if they helpSaturday, June 25, 2011 7:24 PM -
Unnecessary casting is a performance warning when you enable static Code Analysis.Casting is expesnive.Another corrollary situation is:
if (variable is MyType) { MyType typedVariable = (MyType)variable; }
This block of code is why the as operator was invented.The correct way to write this is:MyType typedVariable = variable as MyType; if (typedVariable != null) { }
Every programmer prefers the first block - using the is operator and casting - because it reads easier. But it's a double cast and code analysis will warn you about it because casting is very expensive.EvanSunday, June 26, 2011 3:26 AM