Génériques et de la coulée - ne peut pas lancer de classe héritée de la classe de base
Je sais que c'est vieux, mais je suis toujours pas très bien avec la compréhension de ces problèmes. Quelqu'un peut-il me dire pourquoi le code suivant ne fonctionne pas (jette un runtime
exception sur le casting)?
public abstract class EntityBase { }
public class MyEntity : EntityBase { }
public abstract class RepositoryBase<T> where T : EntityBase { }
public class MyEntityRepository : RepositoryBase<MyEntity> { }
Et maintenant le casting de la ligne:
MyEntityRepository myEntityRepo = GetMyEntityRepo(); //whatever
RepositoryBase<EntityBase> baseRepo = (RepositoryBase<EntityBase>)myEntityRepo;
Donc, quelqu'un peut-il expliquer comment cela est-il invalide? Et, je vous n'êtes pas dans l'humeur pour expliquer - est-il une ligne de code que je peux utiliser pour faire ce casting?
Découvrez C# Covariance et la Contravariance FAQ
Merci à tous pour les réponses. Pour faire court j'ai maintenant résolu ce problème avec une interface de base (RepositoryBase<T> : IRepository). S'avère que j'ai juste besoin pour exécuter les fonctions de l'instance-je laisser la classe se charge lui-même d'autres choses.
Merci à tous pour les réponses. Pour faire court j'ai maintenant résolu ce problème avec une interface de base (RepositoryBase<T> : IRepository). S'avère que j'ai juste besoin pour exécuter les fonctions de l'instance-je laisser la classe se charge lui-même d'autres choses.
OriginalL'auteur Jefim | 2010-08-20
Vous devez vous connecter pour publier un commentaire.
RepositoryBase<EntityBase>
est pas une classe de base deMyEntityRepository
. Vous êtes à la recherche pour la variance générique qui existe en C# dans une mesure limitée, mais ne s'applique pas ici.Supposons que votre
RepositoryBase<T>
classe a une méthode comme ceci:Considérons maintenant:
Maintenant que vous avez ajouté un autre type d'entité à une
MyEntityRepository
... et qui ne peut pas être de droite.Fondamentalement, la variance générique n'est sûr que dans certaines situations. En particulier générique covariance (qui est ce que vous êtes en train de décrire ici) n'est en sécurité lorsque vous ne jamais obtenir les valeurs de "sortie" de l'API; générique contravariance (qui fonctionne en sens inverse) n'est sûr que lorsque l'on n'a jamais mis les valeurs "dans" l'API (par exemple, une comparaison générale qui peut comparer deux formes par zone peut être considérée comme une comparaison des carrés).
En C# 4 cette fonction est disponible pour les interfaces génériques et générique délégués, et non des classes - et uniquement avec les types de référence. Voir MSDN pour de plus amples informations, lire <plug>lire C# en Profondeur, 2e édition, chapitre 13</plug> ou Eric Lippert est blog de la série sur le sujet. Aussi, j'ai donné une heure de parler de ce sujet à la SDN en juillet 2010 - la vidéo est disponible ici.
Il semble que le lien vers votre vidéo a cassé.
Corrigé, merci. Je suis un peu étonné c'est toujours disponible 🙂
OriginalL'auteur Jon Skeet
Chaque fois que quelqu'un pose cette question, j'essaie de prendre leur exemple, et de le traduire à quelque chose en utilisant plus connus des classes qui est évidemment illégal (c'est ce que Jon Skeet a fait dans sa réponse; mais je vais prendre une étape supplémentaire en effectuant cette traduction).
Nous allons remplacer
MyEntityRepository
avecMyStringList
, comme ceci:Maintenant, vous semblez vouloir
MyEntityRepository
être moulage àRepositoryBase<EntityBase>
, le raisonnement étant que ce doit être possible depuisMyEntity
dérive deEntityBase
.Mais
string
dérive deobject
, n'est-ce pas? Ainsi, par cette logique, nous devrions être en mesure de lancer unMyStringList
à unList<object>
.Nous allons voir ce qui peut arriver si nous permettons que...
Uh-oh. Tout à coup, nous sommes énumération sur un
List<string>
et nous tombons sur unRandom
objet. Ce n'est pas bon.J'espère que cela rend la question un peu plus facile à comprendre.
OriginalL'auteur Dan Tao
Cela nécessite de covariance ou de contravariance, dont le soutien est limité .Net, et ne peut pas être utilisé sur les classes abstraites. Vous pouvez utiliser la variance sur les interfaces, donc une possible solution à votre problème est de créer un IRepository que vous utilisez à la place de la classe abstraite.
OriginalL'auteur Mark H