C# 无法将.NET泛型列表转换为其他泛型列表
我正在尝试建立一个C# 无法将.NET泛型列表转换为其他泛型列表,c#,.net,interface,C#,.net,Interface,我正在尝试建立一个lastminute.com.auclone的模型。当我尝试创建一个IProductSearchServices集合时,我得到了所有关于(我猜)方差与协方差等奇怪的错误 我认为,如果任何具体类型实现了相同的接口,并且集合是强类型的,那么我可以使用任何具体类型(对于集合) 这是我要做的代码 private static void Main(string[] args) { // Expected: 3 services in this list. var prod
lastminute.com.au
clone的模型。当我尝试创建一个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....
private static void Main(字符串[]args)
{
//预期:此列表中有3项服务。
var productServices=CreateProductServices();
//归还所有酒店服务。
//预期:此列表中有2项。
var hotelServices=productServices.OfType();
//对于每个酒店服务,请致电SearchAsync。
//在继续之前,等待所有的完成。。。。
WriteLine(“找到{0}个产品。”,…);
}
//在gist中找到完整代码。。。。
这是我的主要错误信息:
这是我的答案
那么问题是什么呢
SearchAsync
注意:我不想使用
dynamic
等。我想尝试将其作为强类型集合来使用。由于注释太有限,我将在回答中发布此内容。它可能无法解决您的问题,但我希望它能让您深入了解代码无法编译的原因。假设您具有以下结构:
class Animal
{
public void Eat();
}
class Cow : Animal
{
public void Moo();
}
牛比动物重要。这意味着,在任何需要动物的地方,你也可以插上一头牛。然而,当预期会有一头母牛时,您不能插入动物,因为动物可能不是母牛,并且不知道如何鸣叫
什么是协方差?
在没有差异的情况下,类型IEnumerable
和IEnumerable
之间没有任何关联,但事实证明它们是相关的:在需要IEnumerable
的地方,我们也可以插入IEnumerable
。为什么呢?因为我们能用IEnumerable做的唯一一件事就是从中提取动物。这就是协方差的语法是out
,动物只通过IEnumerable
返回的原因。我们刚刚得出结论,我们应该能够在任何地方使用奶牛而不是动物,因此,如果可计数的返回奶牛也可以。从这个意义上说,我们期望IEnumerable
从IEnumerable
派生:我们应该能够在需要IEnumerable
的地方插入IEnumerable
。这就是协方差的作用
什么是逆变?
类似地,在没有差异的情况下,Action
和Action
类型不相关。和以前一样,事实证明是这样的,因为一种方法可以给一头奶牛。另一种情况是,通常情况下,取牛的方法不能给动物,因此在这种情况下,关系是另一种情况:Action
应该是Action
的子类型,因为取牛的方法也是取牛的方法,但是,一个方法,采取了一头牛,并不是一个方法,采取了一个动物:它可能想调用的牛穆奥,这是不可能的动物。在中,逆变的语法是,因为逆变类型用作参数;他们不能归还
首先,考虑一个更简单的版本<代码> iBufftSqcService < /C> >具有正确的方差:
public interface IProductSearchService<out TProduct, in TSearchOptions>
where TProduct : IProduct
where TSearchOptions : ISearchOptions
{
TProduct SearchAsync(TSearchOptions searchOptions);
}
这里的问题之一是任务是一个类,而不是一个接口。协方差仅在接口上可用,因此,Task
不能转换为Task
。您可以通过使用而不是任务
来解决这个问题,它是协变的,并提供类似的功能。另外,IList
不是协变的,因此您可以使用IEnumerable
来代替。然而,最大的问题是TSearchOptions
,这是一种反向变量。不能将ipProductSearchService
分配给ipProductSearchService
,因为前者需要SearchAsync
中更具体的参数,而不是不太具体的参数。因此,IPProductSearchService
的列表是没有意义的。您好@RuudvA-感谢您的关注。不过,我不明白你在说什么:(我并不是说你错了-我只是不明白。我认为我的派生类HotelProductSearchService1
是两个泛型,都是派生的。因此,如果两者都是派生的,那么它们都应该可以自动转换到它们的基础上?我很困惑。有代码可以帮助吗?其他人都已经提到了协方差等。我如果您需要在两种类型的列表之间进行转换,一种快速而肮脏的方法是使用“productServices.Cast()”哦,哇!这是一个非常棒的答案,我真的很想知道!好的-这-真的-帮助我现在理解了区别。呸!谢谢。所以我尝试了您所说的。但我仍然得到一个编译时错误。错误屏幕::~~(这是因为IList
中的T
是不可协变的。IList
不是IList
,因为在IList
上调用Add
动物是不可能的。您必须使用IEnumerable
。此外,必须仅获取属性。这也是因为out
类型可以只能返回。在接口的实现中仍然可以有一个setter。我没有得到最后一个不起作用的位。正在尝试将2x hotels+1x flight service添加到集合中。集合是一个列表的列表,对我来说是一个列表
,所以..因此..我应该能够添加一个酒店(即奶牛)或航班(对我来说)收藏品只是说:我想收藏任何至少有一头奶牛的东西
public interface IProductResult<out T> where T : IProduct { ... }
public interface IProductSearchService<out TProduct, in TSearchOptions>
where TProduct : IProduct
where TSearchOptions : ISearchOptions
{
IObservable<IProductResult<TProduct>> SearchAsync(TSearchOptions searchOptions);
}