无法将.NET泛型列表转换为其他通用列表

时间:2014-04-13 05:25:21

标签: c# .net interface

我试图建立lastminute.com.au克隆的模型。当我尝试创建IProductSearchServices的集合时,我得到了所有奇怪的错误(我猜测)方差与协方差等等。

我认为我可以使用任何具体类型(对于集合),如果任何具体类型实现相同的接口并且集合强类型化到同一个接口。

这是我试图做的代码。

private static void Main(string[] args)
{
    // Expected: 3 services in this list.
    var productServices = CreateProductServices();

    // Return all Hotel services.
    // Expected: 2 items in this list.
    var hotelServices = productServices.OfType<??????>();

    // for each hotel service, call SearchAsync.
    // wait for all the finish before continuing....

    Console.WriteLine("Found {0} products.", ....);
}

// Full code found in gist.... 

这是我的主要错误信息......

enter image description here

这是FULL REPO CODE in a GIST

那么问题是什么?

  1. 尝试将3个搜索服务添加到集合中。
  2. 鉴于该列表,我不确定我怎么说:给我所有的酒店服务,这样我就可以SearchAsync了解它们。
  3. 有人可以帮忙吗?

    注意:我不想使用dynamic等。我想尝试将其作为强类型集合等来执行。

1 个答案:

答案 0 :(得分:1)

由于评论的价格太有限,我会在答案中发布。它可能无法解决您的问题,但我希望它能让您深入了解代码无法编译的原因。假设您有以下结构:

class Animal
{
  public void Eat();
}

class Cow : Animal
{
  public void Moo();
}

牛是more specific而不是动物。这意味着无论在哪里都有动物,你也可以插入一头牛。但是,当预计会有牛时,你不能插入动物,因为动物可能不是牛,也不知道如何使用。

什么是协方差?

没有差异,IEnumerable<Animal>IEnumerable<Cow>类型之间没有任何关联,但事实证明它们是:在预期IEnumerable<Animal>的情况下,我们也可以插入{ {1}}。这是为什么?因为IEnumerable<Cow>我们唯一能做的就是从中提取动物。这就是协方差语法为IEnumerable<Animal>的原因,动物仅由out返回。我们刚刚得出结论,我们应该能够在任何地方使用Cow而不是Animal,所以如果可枚举的返回Cows就可以了。从这个意义上讲,我们希望IEnumerable<Animal>来自IEnumerable<Cow>:我们应该能够插入需要IEnumerable<Animal>的{​​{1}}。这就是协方差所做的。

什么是逆转?

同样,如果没有差异,则IEnumerable<Cow>IEnumerable<Animal>类型无关。和以前一样,事实证明它们是,因为一个动物的方法也可以给一个牛。反过来说,一个接受Cow的方法一般不能给Animal,所以在这种情况下,关系是另一种方式:Action<Animal>应该是Action<Cow>的子类型,因为a采用Animal的方法也是采用Cow的方法,但是采用Cow的方法不是采用Animal的方法:它可能想要在Cow上调用Moo,而对于Animal来说这是不可能的。逆变的语法是Action<Animal>,因为逆变类型被用作参数;他们不能归还。

首先,考虑一个更简单的Action<Cow>版本,并且方差正确:

in

很明显IProductSearchService应该是协变的,因为它是返回的。 这意味着public interface IProductSearchService<out TProduct, in TSearchOptions> where TProduct : IProduct where TSearchOptions : ISearchOptions { TProduct SearchAsync(TSearchOptions searchOptions); } TProduct,但不是相反。 因此,IProductSearchService<HotelProduct, T>IProductSearchService<IProduct, T>,但不是相反。

IEnumerable<IProductSearchService<HotelProduct, T>>是逆变的,因为它是一个论证。 这意味着IEnumerable<IProductSearchService<IProduct, T>>TSearchOptions,但不是相反。 因此,IProductSearchService<T, ISearchOptions>IProductSearchService<T, HotelSearchOptions>,但不是相反。 我们可以枚举前者,并使用IEnumerable<IProductSearchService<T, ISearchOptions>>在结果上调用IEnumerable<IProductSearchService<T, HotelSearchOptions>>。但是如果我们枚举后者,SearchAsync期望HotelSearchOptions,那么您就无法插入SearchAsync

正如您所看到的,这些类型的差异是不兼容的,可以将HotelSearchOptions分配给ISearchOptions,但反过来也没有意义。

嵌套协方差

如何修复IEnumerable<IProductSearchService<HotelProduct, ISearchOptions>>的{​​{1}}参数?您必须确保所有嵌套的泛型都是协变的。仅在接口上支持差异,因此您必须将IEnumerable<IProductSearchService<IProduct, HotelSearchOptions>>替换为out。此外,IProductSearchService不是协变的(因为它是一个类),因此您无法使用ProductResultIObservable提供类似的功能,此接口协变。

IProductResult