Sto solo rivedendo il capitolo 4 di C # in Depth che tratta dei tipi nullable e sto aggiungendo una sezione sull'uso dell'operatore "as", che ti permette di scrivere:
object o = ...;
int? x = o as int?;
if (x.HasValue)
{
... // Use x.Value in here
}
Ho pensato che fosse davvero pulito e che potesse migliorare le prestazioni rispetto all'equivalente C # 1, usando "is" seguito da un cast - dopotutto, in questo modo dobbiamo solo chiedere il controllo dinamico del tipo una volta, quindi un semplice controllo del valore .
Questo sembra non essere il caso, tuttavia. Di seguito ho incluso un'app di prova di esempio, che in sostanza somma tutti gli interi all'interno di un array di oggetti, ma l'array contiene molti riferimenti null e riferimenti a stringhe nonché numeri interi in scatola. Il benchmark misura il codice che dovresti usare in C # 1, il codice usando l'operatore "as" e solo per dare il via a una soluzione LINQ. Con mio stupore, il codice C # 1 è 20 volte più veloce in questo caso - e persino il codice LINQ (che mi sarei aspettato fosse più lento, dati gli iteratori coinvolti) batte il codice "as".
L'implementazione di .NET isinst
per tipi nullable è davvero lenta? È l'ulteriore unbox.any
che causa il problema? C'è un'altra spiegazione per questo? Al momento sembra che dovrò includere un avvertimento contro l'utilizzo in situazioni sensibili alle prestazioni ...
risultati:
Cast: 10000000: 121
As: 10000000: 2211
LINQ: 10000000: 2143
Codice:
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
su tipi nullable. Interessante, in quanto non può essere utilizzato su altri tipi di valore. In realtà, più sorprendente.
as
tenta di eseguire il cast su un tipo e se fallisce restituisce null. Non puoi impostare i tipi di valore su null