Estou apenas revisando o capítulo 4 do C # no Depth, que trata de tipos anuláveis, e estou adicionando uma seção sobre o uso do operador "as", que permite escrever:
object o = ...;
int? x = o as int?;
if (x.HasValue)
{
... // Use x.Value in here
}
Eu pensei que isso era realmente legal e que poderia melhorar o desempenho em relação ao equivalente em C # 1, usando "is" seguido de uma conversão - afinal, dessa forma, só precisamos solicitar uma verificação dinâmica de tipo uma vez e depois uma simples verificação de valor .
No entanto, parece não ser esse o caso. Incluí um exemplo de aplicativo de teste abaixo, que basicamente soma todos os números inteiros em uma matriz de objetos - mas a matriz contém muitas referências nulas e referências de string, bem como números inteiros em caixa. A referência mede o código que você teria que usar no C # 1, o código usando o operador "as" e apenas para dar um pontapé na solução LINQ. Para minha surpresa, o código C # 1 é 20 vezes mais rápido nesse caso - e até o código LINQ (que eu esperava ser mais lento, considerando os iteradores envolvidos) supera o código "como".
A implementação do .NET isinst
para tipos anuláveis é realmente muito lenta? É o adicionalunbox.any
que causa o problema? Existe outra explicação para isso? No momento, parece que vou ter que incluir um aviso contra o uso em situações sensíveis ao desempenho ...
Resultados:
Elenco: 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
em tipos anuláveis. Interessante, pois não pode ser usado em outros tipos de valor. Na verdade, mais surpreendente.
as
tente converter para um tipo e, se falhar, retornará nulo. Não é possível definir os tipos de valor para nulo