Quelle est la performance frappée par le downcasting?
Question
J'essaie simplement de comprendre les génériques en lisant cet article édifiant de Juval Lowy
Paraphrasant .. Lorsque vous définissez une définition de classe générique, celle-ci est compilée en IL.
- Pour les types de valeur, dès que vous demandez un type de valeur spécifique, il remplace le T par votre type de valeur spécifique pour obtenir le IL pour cette configuration spécifique, par exemple.
MyList<int>
Avantage: pas de pénalité de boxe et de déballage. - Tout va bien .. pour les types de référence, le compilateur remplace toutes les instances de T dans votre définition avec Object et crée le IL utilisé pour tous les types de référence. Les instances sont toutefois allouées en fonction du type de référence demandé réel, par exemple.
MyList<String>
Nous avons maintenant des méthodes génériques utilisant des Object
paramètres. Generics demande une amélioration de ses performances de 100%, car " cela évite la pénalité de performances que vous subissez lorsque vous convertissez le type d'objet à votre type spécifique lorsque vous souhaitez l'utiliser"
// assume GetItem returns an Object
string sMyPreciousString = (string) obList.GetItem();
Quelle est cette performance affectée lorsque vous passez de Object à un type de référence spécifique? De plus, il semble que la transformation en Object (même si Generics le ferait) n’est pas un succès en termes de performances. Pourquoi?
La solution
La conversion ascendante en objet ne nécessite pas de vérification du temps d'exécution - elle fonctionnera toujours et sera en principe non-opératoire.
Le downcasting nécessite une vérification du temps d'exécution pour vous assurer que vous ne transcrivez pas un flux en chaîne par exemple. Il s’agit d’une pénalité minime et peu susceptible de constituer un goulet d’étranglement - mais l’éviter n’est qu’un avantage supplémentaire pour les génériques.
Autres conseils
L’atteinte des performances provient de la nécessité d’une vérification du type à l’exécution. Si B est une sous-classe de A, alors lorsque vous convertissez un B en A, vous savez au moment de la compilation qu'il sera en sécurité, car tous les Bs sont en tant que. Par conséquent, vous n'avez pas besoin de générer de code d'exécution pour vérifier le type.
Cependant, lorsque vous convertissez un A en B, vous ne savez pas au moment de la compilation si ce dernier est réellement un B ou non. Il peut s'agir simplement d'un A, il peut s'agir d'un type C, d'un sous-type différent de A. Par conséquent, vous devez générer un code d'exécution qui garantira que l'objet est bien un B et lève une exception s'il ne l'est pas.
Les génériques ne rencontrent pas ce problème, car le compilateur sait que, lors de la compilation, seuls B sont insérés dans la structure de données. Ainsi, lorsque vous extrayez quelque chose, le compilateur sait que ce sera un B, il n'y a donc pas besoin de la vérification de type au moment de l'exécution.
Lecture de l’IL qui est généré (cet article le dit bien). .. aha - isinst.
Si vous n'étiez pas en aval, vous n'auriez pas à appeler isinst .