我试图建立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....
这是我的主要错误信息......
那么问题是什么?
SearchAsync
了解它们。有人可以帮忙吗?
注意:我不想使用dynamic
等。我想尝试将其作为强类型集合等来执行。
答案 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
不是协变的(因为它是一个类),因此您无法使用ProductResult
。 IObservable
提供类似的功能,此接口是协变。
IProductResult