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?

Était-ce utile?

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.

Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top