两者之间是否有任何可测量的性能差异
((TypeA) obj).method1(); ((TypeA) obj).method2(); ((TypeA) obj).method3();
和
var A = (TypeA) obj; A.method1(); A.method2(); A.method3();
什么时候使用?
我经常看到类似的东西
if (((TextBox)sender).Text.Contains('.') || ((TextBox)sender).Text.Contains(','))
并想知道这是否是对性能的浪费.
如果用很少的其他工作完成数十亿次,这可能是可测量的.我不知道CLR是否会有效地缓存转换工作的事实,因此它不需要再次执行 - 如果它现在不这样做,它可能会在以后的版本中这样做.它可能在64位JIT但不是32位版本中这样做,反之亦然 - 你明白了.我怀疑它会在普通代码中产生重大影响.
我个人更喜欢第二种形式的可读性,而且到目前为止更为重要.
@dkson:我测试了两种方法.这是我在计算机上找到的内容:
他们对相同的性能.事实上,我发现第二种方法稍慢.原因(我相信)是额外变量和初始演员的成本.当然,如果你使用足够的演员阵容,你可能会获得性能成本.只有在节省了20-30次演员之后,你才能在表演方面实现收支平衡.
以下是最近两次测试运行的结果:
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
我也测试了castclass
和之间的区别isinst
.根据我读过的内容:
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
我认为即使没有例外,isinst也会比castclass快.但是,在创建自己的基准测试后,我发现isinst 比castclass 略慢.很有意思.这是我的结果:
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
所以,斯基特先生,我的立场得到了纠正.
环境:
Windows Vista
最高核心速度3.2Ghz
.NET Framework v2.0.50727
以下是我创建和运行的基准测试的完整来源:(使用此处提供的Jon Skeets Microbenchmarking框架)
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++) { //Simulate 3 x 10 method calls while casting for (int y = 0; y < 10; y++) { ((DerivedType)TestBaseType).TestDerivedMethod(); ((DerivedType)TestBaseType).TestDerivedMethod2(); ((DerivedType)TestBaseType).TestDerivedMethod3(); } } } [Benchmark] public static void TestSingleCast_30x() { BaseType TestBaseType = new DerivedType(); for (int x = 0; x < Iterations; x++) { DerivedType TestDerivedType = (DerivedType)TestBaseType; //Simulate 3 x 10 method calls on already-cast object for (int y = 0; y < 10; y++) { TestDerivedType.TestDerivedMethod(); TestDerivedType.TestDerivedMethod2(); TestDerivedType.TestDerivedMethod3(); } } } [Benchmark] public static void TestEmptyLoop() { for (int x = 0; x < Iterations; x++) { } } [Benchmark] public static void TestDCast_castclass() { BaseType TestDerivedType = new DerivedType(); for (int x = 0; x < Iterations; x++) { ((DerivedType)TestDerivedType).TestDerivedMethod(); } } [Benchmark] public static void TestDCast_isinst() { BaseType TestDerivedType = new DerivedType(); for (int x = 0; x < Iterations; x++) { (TestDerivedType as DerivedType).TestDerivedMethod(); } } }
由此产生的IL isinst
和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 }