try safe que operator objeto convert como castear cast c# .net performance types

safe - que es cast en c#



Rendimiento de TypeCasting (2)

¿Hay alguna diferencia de rendimiento apreciable entre

((TypeA) obj).method1(); ((TypeA) obj).method2(); ((TypeA) obj).method3();

y

var A = (TypeA) obj; A.method1(); A.method2(); A.method3();

cuando se usa muchas veces?

A menudo veo algo como

if (((TextBox)sender).Text.Contains(''.'') || ((TextBox)sender).Text.Contains('',''))

y me pregunto si esto es un desperdicio de rendimiento.


@dkson: Probé ambos métodos. Esto es lo que encontré en mi computadora:

Son casi iguales en el rendimiento. De hecho, el segundo método me pareció un poco más lento. La razón (creo) es el costo de la variable adicional y el lanzamiento inicial. Por supuesto, si usa suficientes moldes puede recuperar ese costo de rendimiento. Parece que usted gana el equilibrio en términos de rendimiento solo después de ahorrar entre 20 y 30 lanzamientos.

Aquí están los resultados de las dos pruebas más recientes:

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

También probé la diferencia entre castclass y isinst . Basado en lo que había leído:

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

Pensé que esto sería más rápido que castclass, incluso cuando no hubiera excepciones. Sin embargo, después de crear mis propios puntos de referencia, encontré que isinst es un poco más lento que castclass. Muy interesante. Aquí están mis resultados:

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

Entonces, Sr. Skeet, estoy corregido.

Ambiente:

Windows Vista
Velocidad Máxima de Núcleo 3.2GHz
.NET Framework v2.0.50727

Aquí está la fuente completa de los puntos de referencia que creé y ejecuté: (hace uso del marco de Microbenchmarking de Jon Skeets disponible 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++) { //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(); } } }

Y la IL resultante para los métodos isinst y 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 }


Puede ser medible si se está haciendo miles de millones de veces con muy poco otro trabajo. No sé si el CLR efectivamente almacenará en caché el hecho de que el reparto funcionó, por lo que no necesita hacerlo de nuevo; si no lo hace ahora, podría hacerlo en una versión posterior. Puede hacerlo en el JIT de 64 bits, pero no en la versión de 32 bits, o viceversa: se entiende la idea. Sin embargo, dudo que haga una diferencia significativa en el código normal.

Personalmente, me gusta más la legibilidad de la segunda forma, y ​​eso es mucho más importante.