Préface: Je suis conscient qu'il y a beaucoup de questions et de réponses sur la covariance et la contravariance, mais je me sens encore confus et je ne sais pas quelle solution mettre en œuvre.Confusion de covariance. Impossible d'affecter des tuples d'interfaces implémentées à la liste des tuples
J'ai deux interfaces dont les implémentations sont destinées à être utilisées ensemble par paires. L'un fournit les informations sur un élément de vente et l'autre fournit des informations dépendantes de la langue pour un élément de vente.
Je n'ai pas de contrôle sur ces interfaces:
public interface IItem
{
decimal Price { get; set; }
}
public interface IItemTranslation
{
string DisplayName { get; set; }
}
J'ai aussi deux implémentations de ces deux interfaces pour une GoodsItem
tangible ainsi qu'une ServiceItem
intangible. Encore une fois, Je n'ai pas de contrôle sur ces interfaces:
public class GoodsItem : IItem
{
public decimal Price { get; set; } //implementation
public float ShippingWeightKilograms { get; set; } //Property specific to a GoodsItem
}
public class GoodsTranslation : IItemTranslation
{
public string DisplayName { get; set; } //implementation
public Uri ImageUri { get; set; } //Property specific to a GoodsTranslation
}
public class ServiceItem : IItem
{
public decimal Price { get; set; } //implementation
public int ServiceProviderId { get; set; } // Property specific to a ServiceItem
}
public class ServiceTranslation : IItemTranslation
{
public string DisplayName { get; set; } //implementation
public string ProviderDescription { get; set; } // Property specific to a ServiceTranslation
}
Comme je l'ai dit, ce sont les classes que je n'ai pas le contrôle. Je veux créer une liste générique de ces appariements (List<Tuple<IItem, IItemTranslation>>
) mais je ne peux pas:
public class StockDisplayList
{
public List<Tuple<IItem, IItemTranslation>> Items { get; set; }
public void AddSomeStockItems()
{
Items = new List<Tuple<IItem, IItemTranslation>>();
var canOfBeans = new Tuple<GoodsItem, GoodsTranslation>(new GoodsItem(), new GoodsTranslation());
var massage = new Tuple<ServiceItem, ServiceTranslation>(new ServiceItem(), new ServiceTranslation());
Items.Add(canOfBeans); //illegal: cannot convert from 'Tuple<GoodsItem, GoodsTranslation>' to 'Tuple<IItem, IItemTranslation>'
Items.Add(massage); //illegal: cannot convert from 'Tuple<ServiceItem, ServiceTranslation>' to 'Tuple<IItem, IItemTranslation>' }
}
Question: Sans changer mes IItem
et ITranslation
classes ou leurs types dérivés, quelle est la manière la plus propre pour être en mesure de passer autour une liste générique de ces appariements sans les retourner entre l'interface et leur type?
Avertissement. J'essayais de simplifier la question mais je n'utilise pas vraiment Tuples. En réalité, j'utilise une classe comme ceci:
public class ItemAndTranslationPair<TItem, TItemTranslation> where TItem : class, IItem where TItemTranslation : class, IItemTranslation
{
TItem Item;
TTranslation Translation;
}
et mes services reviennent listes fortement typé, comme List<ItemAndTranslationPair<GoodsItem, GoodsTranslation>>
et donc quand j'ajouter des articles à la liste « générique », il ressemble à:
var differentBrandsOfBeans = SomeService.GetCansOfBeans();
//above variable is of type IEnumerable<ItemAndTranslationPair<GoodsItem, GoodsTranslation>>
var items = new List<ItemAndTranslationPair<IItem, IItemTranslation>>();
items.AddRange(differentBrandsOfBeans);
Merci beaucoup pour votre réponse. Mais comment pourrais-je réellement instancier un de ces appariements? par exemple. dans la méthode 'GetCansOfBeans()' quelle implémentation de 'IReadableItemAndTranslationPair' est-ce que j'utilise? C'est là que je me perds avec d'autres QA en ligne pour la covariance et le modificateur 'out'. – Zac
@Zac Vous devriez avoir une classe telle que 'class ItemAndTranslationPair' qui implémente l'interface 'IReadableItemAndTranslationPair '. La classe pourrait avoir à la fois 'get' et' set' pour ses propriétés (seule la partie 'get' ferait partie de l'interface" contract "). Le type de retour de la méthode 'GetCansOfBeans()' devrait impliquer seulement l'interface, mais les paires réelles que vous "cédez" devraient être des instances de la classe. –
Cheers @Jeppe. Avoir à la fois la partie 'get' et' set' sur la mise en œuvre tout en ayant seulement 'get' sur le contrat était l'endroit où je devenais confus. Je peux vivre avec ma méthode 'GetCansOfBeans()' retournant l'interface, bien que mes autres méthodes comme 'DeleteCansOfBeans (IEnumerable>)' ne fonctionneront probablement plus avec ces listes, ce qui semble insatisfaisant. –
Zac