代码之家  ›  专栏  ›  技术社区  ›  Zac

协方差混乱。无法将已实现接口的元组分配给元组列表

  •  0
  • Zac  · 技术社区  · 8 年前

    前言:我知道有很多关于协方差和逆方差的问题和答案,但我仍然感到困惑,不确定要实现什么解决方案。

    我有两个接口,它们的实现旨在成对使用。一个提供有关销售项目的信息,另一个提供销售项目的语言相关信息。

    我无法控制这些接口 :

    public interface IItem
    {
        decimal Price { get; set; }
    }
    
    public interface IItemTranslation
    {
        string DisplayName { get; set; }
    }
    

    我还为有形的 GoodsItem 以及无形的 ServiceItem 再一次 我无法控制这些接口 :

    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
    }
    

    正如我所说,这些是我无法控制的类。我想创建这些配对的通用列表( List<Tuple<IItem, IItemTranslation>> )但我不能:

    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>'    }
    }
    

    问题 A:不改变我的 IItem ITranslation 类或它们的派生类型,有什么最干净的方法可以传递这些对的泛型列表,而不在接口和类型之间来回转换它们?

    警告我试图简化这个问题,但实际上我没有使用元组。实际上,我使用的是这样一个类:

    public class ItemAndTranslationPair<TItem, TItemTranslation> where TItem : class, IItem where TItemTranslation : class, IItemTranslation
    {
        TItem Item;
        TTranslation Translation;
    }
    

    我的服务返回强类型列表,比如 List<ItemAndTranslationPair<GoodsItem, GoodsTranslation>> 因此,当我将项目添加到“通用”列表时,它看起来像:

    var differentBrandsOfBeans = SomeService.GetCansOfBeans();
    //above variable is of type IEnumerable<ItemAndTranslationPair<GoodsItem, GoodsTranslation>>
    
    var items = new List<ItemAndTranslationPair<IItem, IItemTranslation>>();
    items.AddRange(differentBrandsOfBeans);
    
    2 回复  |  直到 8 年前
        1
  •  2
  •   Sean    8 年前

    您需要使用以下接口类型创建元组:

    var canOfBeans = new Tuple<IItem, IItemTranslation>(new GoodsItem(), new GoodsTranslation());
    var massage = new Tuple<IItem, IItemTranslation>(new ServiceItem(), new ServiceTranslation());
    

    当您将它们存储在以下列表中时: Tuple<IItem, IItemTranslation> 这对你来说应该是个问题。

        2
  •  1
  •   Jeppe Stig Nielsen    8 年前

    使用 out 要获取的泛型类型的类型参数上的修饰符 协方差 在该参数中。

    在当前版本的C#中,不支持 class 类型,仅 interface 类型(和委托类型),因此您需要编写一个接口(注意 出来 ):

    public interface IReadableItemAndTranslationPair<out TItem, out TItemTranslation>
      where TItem : class, IItem
      where TItemTranslation : class, IItemTranslation
    {
      TItem Item { get; }
      TItemTranslation Translation { get; }
    }
    

    请注意,属性不能具有 set 因为这与协方差不兼容。

    使用此类型,您可以:

    var differentBrandsOfBeans = SomeService.GetCansOfBeans();
    //above variable is of type
    //IEnumerable<IReadableItemAndTranslationPair<GoodsItem, GoodsTranslation>>
    
    var items = new List<IReadableItemAndTranslationPair<IItem, IItemTranslation>>();
    
    items.AddRange(differentBrandsOfBeans);
    

    它之所以有效是因为 IEnumerable<out T> 是协变的,你的类型 IReadableItemAndTranslationPair<out TItem, out TItemTranslation> 两者都是协变的 TItem TItemTranslation .