Solo estoy revisando el capítulo 4 de C # en profundidad, que trata sobre los tipos anulables, y estoy agregando una sección sobre el uso del operador "como", que le permite escribir:
object o = ...;
int? x = o as int?;
if (x.HasValue)
{
... // Use x.Value in here
}
Pensé que esto era realmente bueno, y que podría mejorar el rendimiento sobre el equivalente de C # 1, usando "es" seguido de un reparto; después de todo, de esta manera solo necesitamos pedir una verificación de tipo dinámico una vez, y luego una simple verificación de valor .
Sin embargo, este no parece ser el caso. He incluido una aplicación de prueba de muestra a continuación, que básicamente suma todos los enteros dentro de una matriz de objetos, pero la matriz contiene muchas referencias nulas y referencias de cadenas, así como enteros en caja. El punto de referencia mide el código que tendría que usar en C # 1, el código que usa el operador "como", y solo por una solución LINQ. Para mi sorpresa, el código C # 1 es 20 veces más rápido en este caso, e incluso el código LINQ (que hubiera esperado que fuera más lento, dados los iteradores involucrados) supera el código "como".
¿La implementación de .NET isinst
para tipos anulables es realmente lenta? ¿Es el adicional unbox.any
que causa el problema? ¿Hay otra explicación para esto? Por el momento parece que voy a tener que incluir una advertencia contra el uso de esto en situaciones sensibles al rendimiento ...
Resultados:
Reparto: 10000000: 121
Como: 10000000: 2211
LINQ: 10000000: 2143
Código:
using System;
using System.Diagnostics;
using System.Linq;
class Test
{
const int Size = 30000000;
static void Main()
{
object[] values = new object[Size];
for (int i = 0; i < Size - 2; i += 3)
{
values[i] = null;
values[i+1] = "";
values[i+2] = 1;
}
FindSumWithCast(values);
FindSumWithAs(values);
FindSumWithLinq(values);
}
static void FindSumWithCast(object[] values)
{
Stopwatch sw = Stopwatch.StartNew();
int sum = 0;
foreach (object o in values)
{
if (o is int)
{
int x = (int) o;
sum += x;
}
}
sw.Stop();
Console.WriteLine("Cast: {0} : {1}", sum,
(long) sw.ElapsedMilliseconds);
}
static void FindSumWithAs(object[] values)
{
Stopwatch sw = Stopwatch.StartNew();
int sum = 0;
foreach (object o in values)
{
int? x = o as int?;
if (x.HasValue)
{
sum += x.Value;
}
}
sw.Stop();
Console.WriteLine("As: {0} : {1}", sum,
(long) sw.ElapsedMilliseconds);
}
static void FindSumWithLinq(object[] values)
{
Stopwatch sw = Stopwatch.StartNew();
int sum = values.OfType<int>().Sum();
sw.Stop();
Console.WriteLine("LINQ: {0} : {1}", sum,
(long) sw.ElapsedMilliseconds);
}
}
as
en tipos anulables. Interesante, ya que no se puede usar en otros tipos de valor. En realidad, más sorprendente.
as
intenta convertir a un tipo y, si falla, devuelve nulo. No puede establecer los tipos de valor en nulo