Je ne comprends pas pourquoi le code C # suivant ne se compile pas.
Comme vous pouvez le voir, j'ai une méthode générique statique Something avec un IEnumerable<T>
paramètre (et T
est contraint d'être une IA
interface), et ce paramètre ne peut pas être converti implicitement en IEnumerable<IA>
.
Quelle est l'explication? (Je ne recherche 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 que je reçois en Something2(bar)
ligne:
Argument 1: impossible de convertir de «System.Collections.Generic.List» en «System.Collections.Generic.IEnumerable»
c#
covariance
contravariance
BenLaz
la source
la source
T
aux types de référence. Si vous utilisez la condition,where T: class, IA
cela devrait fonctionner. La réponse liée a plus de détails.Something2(foo);
directement. Il n'est pas nécessaire de faire le tour.ToList()
pour obtenir unList<T>
(T
votre paramètre de type est-il déclaré par la méthode générique) pour comprendre cela (aList<T>
est unIEnumerable<T>
).Réponses:
Le message d'erreur n'est pas suffisamment informatif, et c'est 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" en ce moment. Oui, ça l'est. Mais vous n'avez pas dit queT
c'était égal àIA
. Vous avez dit queT
c'est un type qui implémenteIA
, et qu'un type valeur peut implémenter une interface . Par conséquent, nous ne savons pas si la covariance fonctionnera et nous la rejetons.Si vous voulez que la covariance fonctionne, vous devez indiquer au compilateur que le paramètre de type est un type de référence avec la
class
contrainte ainsi que laIA
contrainte d'interface.Le message d'erreur devrait vraiment dire que la conversion n'est pas possible car la covariance nécessite une garantie de type de référence, puisque c'est le problème fondamental.
la source
customers.Select(c=>c.FristName)
? La spécification C # indique très clairement qu'il s'agit d'une erreur de résolution de surcharge : l'ensemble des méthodes applicables nommées Select qui peuvent accepter ce lambda est vide. Mais la cause première est qu'il yFirstName
a une faute de frappe.Je voulais juste compléter l'excellente réponse d'initié d'Eric avec un exemple de code pour ceux qui ne sont peut-être pas familiers avec les contraintes génériques.
Changez
Something
la signature de la manière suivante: laclass
contrainte doit venir en premier .la source
primary_constraint ',' secondary_constraints ',' constructor_constraint
class
est mauvais car cela signifie «type de référence», pas «classe». J'aurais été plus heureux avec quelque chose de verbeux commewhere T is not struct