Erreur de conversion de type C # malgré la contrainte générique
-
06-07-2019 - |
Question
Pourquoi, avec une contrainte générique sur le paramètre de type T de la classe P de & "; doit hériter de A &" ;, le premier appel aboutit-il mais le second appel échoue avec l'erreur de conversion de type détaillée dans le commentaire:
abstract class A { }
static class S
{
public static void DoFirst(A argument) { }
public static void DoSecond(ICollection<A> argument) { }
}
static class P<T>
where T : A, new()
{
static void Do()
{
S.DoFirst(new T()); // this call is OK
S.DoSecond(new List<T>()); // this call won't compile with:
/* cannot convert from 'System.Collections.Generic.List<T>'
to 'System.Collections.Generic.ICollection<A>' */
}
}
La contrainte générique ne devrait-elle pas garantir que List<T>
est bien ICollection<A>
?
La solution
Ceci est un exemple de l'absence de covariance sur les types génériques de C # (C #). prend en charge la covariance des tableaux). C # 4 ajoutera cette fonctionnalité aux types d’interface et mettra également à jour plusieurs types d’interface BCL pour la prendre en charge.
Veuillez consulter C # 4.0: Covariance et Contravariance :
Dans cet article, je & # 8217; vais essayer de couvrir un des innovations C # 4.0. Un de les nouvelles fonctionnalités est la covariance et contravariance sur les paramètres de type qui est maintenant soutenu par des délégués génériques et interfaces génériques. Commençons par & # 8217; s voyez ce que signifient ces mots:)
Autres conseils
La contrainte n'a aucun effet sur le problème. le problème est que vous passez une liste dans un paramètre qui nécessite ICollection - C # ne supporte pas la covariance, vous devez donc explicitement convertir la liste en ICollection:
S.DoSecond((ICollection<A>) new List<T>()); // this call will be happy
Vous avez fortement saisi le paramètre pour DoSecond en tant que type ICollection < A > ;. Malgré le fait que T soit du type A, au moment de la compilation, il n’existe pas de transtypage implicite entre List & Lt; T & Gt; et ICollection < A > ;. Vous devrez soit créer la liste et la convertir en ICollection & Lt; A & Gt; lorsque vous appelez DoSecond ou faites de DoSecond une méthode générique elle-même.
REMARQUE: ce type de distribution implicite doit être pris en charge en C # 4.0, ce qui permettra d'améliorer considérablement la corrélation / la variance par rapport aux offres de C # 3.0.