@dkson: I tested both methods. Here is what I found on my computer:
They are about the same in performance. In fact, the second method I discovered is a bit slower. The reason (I believe) is the cost of the extra variable and the initial throw. Of course, if you use a sufficient number of throws, you can return this cost. It seems that you break even in terms of performance only after saving 20-30 throws.
The following are the results of the last two test runs:
TestMuliCast\_3x: 00:00:00.5970000 TestSingleCast\_3x: 00:00:00.6020000 TestMuliCast\_30x: 00:00:06.0930000 TestSingleCast\_30x: 00:00:06.0480000 TestMuliCast\_3x: 00:00:00.6120000 TestSingleCast\_3x: 00:00:00.6250000 TestMuliCast\_30x: 00:00:06.5490000 TestSingleCast\_30x: 00:00:06.4440000
I also checked the difference between castclass and isinst . Based on what I read:
http://m3mia.blogspot.com/2007/11/comparing-isinst-to-castclass.html
http://www.codeproject.com/KB/cs/csharpcasts.aspx
http://discuss.joelonsoftware.com/default.asp?dotnet.12.635066.13
I thought that isinst would be faster than castclass, even if there were no exceptions. However, after creating my own tests, I found that it was a bit slower than castclass. Very interesting. Here are my results:
TestEmptyLoop: 00:00:00.0870000 TestDCast\_castclass: 00:00:00.2640000 TestDCast\_isinst: 00:00:00.3780000 TestEmptyLoop: 00:00:00.0870000 TestDCast\_castclass: 00:00:00.2600000 TestDCast\_isinst: 00:00:00.3750000
So, Mr. Skeet, I'm standing corrected.
Environment:
Windows Vista
Maximum core frequency 3.2 GHz
.NET Framework v2.0.50727
Here is the complete source of the tests I created and ran: (uses the available Jon Skeets microplate infrastructure here )
using System; using System.Collections; public class CastingBenchmark { static Int64 Iterations=100000000; static Int64 TestWork = 0; public static void Init(string[] args) { if (args.Length>0) Iterations = Int64.Parse(args[0]); } public static void Reset() { TestWork = 0; } internal class BaseType { public void TestBaseMethod() { TestWork++; } } internal class DerivedType : BaseType { public void TestDerivedMethod() { TestWork++; } public void TestDerivedMethod2() { TestWork++; } public void TestDerivedMethod3() { TestWork++; } } [Benchmark] public static void TestMuliCast_3x() { BaseType TestBaseType = new DerivedType(); for (int x = 0; x < Iterations; x++) { ((DerivedType)TestBaseType).TestDerivedMethod(); ((DerivedType)TestBaseType).TestDerivedMethod2(); ((DerivedType)TestBaseType).TestDerivedMethod3(); } } [Benchmark] public static void TestSingleCast_3x() { BaseType TestBaseType = new DerivedType(); for (int x = 0; x < Iterations; x++) { DerivedType TestDerivedType = (DerivedType)TestBaseType; TestDerivedType.TestDerivedMethod(); TestDerivedType.TestDerivedMethod2(); TestDerivedType.TestDerivedMethod3(); } } [Benchmark] public static void TestMuliCast_30x() { BaseType TestBaseType = new DerivedType(); for (int x = 0; x < Iterations; x++) {
And the resulting IL for the isinst and castclass :
method public hidebysig static void TestDCast_isinst() cil managed { .custom instance void BenchmarkAttribute::.ctor() .maxstack 2 .locals init ( [0] class CastingBenchmark/BaseType TestDerivedType, [1] int32 x) L_0000: newobj instance void CastingBenchmark/DerivedType::.ctor() L_0005: stloc.0 L_0006: ldc.i4.0 L_0007: stloc.1 L_0008: br.s L_0019 L_000a: ldloc.0 L_000b: isinst CastingBenchmark/DerivedType L_0010: callvirt instance void CastingBenchmark/DerivedType::TestDerivedMethod() L_0015: ldloc.1 L_0016: ldc.i4.1 L_0017: add L_0018: stloc.1 L_0019: ldloc.1 L_001a: conv.i8 L_001b: ldsfld int64 CastingBenchmark::Iterations L_0020: blt.s L_000a L_0022: ret } .method public hidebysig static void TestDCast_castclass() cil managed { .custom instance void BenchmarkAttribute::.ctor() .maxstack 2 .locals init ( [0] class CastingBenchmark/BaseType TestDerivedType, [1] int32 x) L_0000: newobj instance void CastingBenchmark/DerivedType::.ctor() L_0005: stloc.0 L_0006: ldc.i4.0 L_0007: stloc.1 L_0008: br.s L_0019 L_000a: ldloc.0 L_000b: castclass CastingBenchmark/DerivedType L_0010: callvirt instance void CastingBenchmark/DerivedType::TestDerivedMethod() L_0015: ldloc.1 L_0016: ldc.i4.1 L_0017: add L_0018: stloc.1 L_0019: ldloc.1 L_001a: conv.i8 L_001b: ldsfld int64 CastingBenchmark::Iterations L_0020: blt.s L_000a L_0022: ret }