Je suis en train de réviser le chapitre 4 de C # en profondeur qui traite des types nullables, et j'ajoute une section sur l'utilisation de l'opérateur "as", qui vous permet d'écrire:
object o = ...;
int? x = o as int?;
if (x.HasValue)
{
... // Use x.Value in here
}
Je pensais que c'était vraiment bien, et que cela pourrait améliorer les performances par rapport à l'équivalent C # 1, en utilisant "est" suivi d'un cast - après tout, de cette façon, nous n'avons besoin de demander une vérification de type dynamique qu'une seule fois, puis une simple vérification de valeur .
Cependant, cela ne semble pas être le cas. J'ai inclus un exemple d'application de test ci-dessous, qui résume essentiellement tous les entiers dans un tableau d'objets - mais le tableau contient de nombreuses références nulles et des références de chaîne ainsi que des entiers encadrés. Le benchmark mesure le code que vous auriez à utiliser en C # 1, le code utilisant l'opérateur "as", et juste pour lancer une solution LINQ. À mon grand étonnement, le code C # 1 est 20 fois plus rapide dans ce cas - et même le code LINQ (qui je m'attendais à être plus lent, étant donné les itérateurs impliqués) bat le code "as".
L'implémentation .NET des isinst
types nullables est-elle vraiment très lente? Est-ce le supplément unbox.any
qui cause le problème? Y a-t-il une autre explication à cela? Pour le moment, je pense que je vais devoir inclure un avertissement contre l'utilisation de ceci dans des situations sensibles aux performances ...
Résultats:
Distribution: 10000000: 121
Comme: 10000000: 2211
LINQ: 10000000: 2143
Code:
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
types nullables. Intéressant, car il ne peut pas être utilisé sur d'autres types de valeur. En fait, plus surprenant.
as
essayez de transtyper en un type et s'il échoue, il retourne null. Vous ne pouvez pas définir les types de valeurs sur null