Je ne comprends pas pourquoi le code C # suivant ne compile pas.
Comme vous pouvez le voir, j'ai une méthode générique statique Quelque chose avec un paramètre IEnumerable<T>
(et T
est contraint d'être une interface IA
), et ce paramètre ne peut pas être converti implicitement en IEnumerable<IA>
.
Quelle est l'explication? (Je ne cherche pas de solution de contournement, juste pour comprendre pourquoi cela ne fonctionne pas).
public interface IA { }
public interface IB : IA { }
public class CIA : IA { }
public class CIAD : CIA { }
public class CIB : IB { }
public class CIBD : CIB { }
public static class Test
{
public static IList<T> Something<T>(IEnumerable<T> foo) where T : IA
{
var bar = foo.ToList();
// All those calls are legal
Something2(new List<IA>());
Something2(new List<IB>());
Something2(new List<CIA>());
Something2(new List<CIAD>());
Something2(new List<CIB>());
Something2(new List<CIBD>());
Something2(bar.Cast<IA>());
// This call is illegal
Something2(bar);
return bar;
}
private static void Something2(IEnumerable<IA> foo)
{
}
}
Erreur je rentre dans la ligne Something2(bar)
:
Argument 1: impossible de convertir 'System.Collections.Generic.List' en 'System.Collections.Generic.IEnumerable'
Le message d'erreur est insuffisamment informatif, et c'est de ma faute. Désolé pour ça.
Le problème que vous rencontrez est une conséquence du fait que la covariance ne fonctionne que sur les types de référence.
Vous dites probablement "mais IA
est un type de référence" pour le moment. Oui, ça l'est. Mais vous n'avez pas dit que T
est égal à IA
. Vous avez dit que T
est un type qui implémente IA
et n type valeur peut implémenter une interface. Par conséquent, nous ne savons pas si la covariance fonctionnera et nous la refusons.
Si vous voulez que la covariance fonctionne, vous devez indiquer au compilateur que le paramètre type est un type de référence avec la contrainte class
ainsi que la contrainte d'interface IA
.
Le message d'erreur devrait en réalité indiquer que la conversion n'est pas possible car la covariance nécessite une garantie de type référence-type, car c'est le problème fondamental.
Je voulais simplement compléter l'excellente réponse d'initié d'Eric avec un exemple de code pour ceux qui ne sont peut-être pas familiarisés avec les contraintes génériques.
Changez la signature de Something
comme ceci: La contrainte class
doit venir en premier.
public static IList<T> Something<T>(IEnumerable<T> foo) where T : class, IA