Linq 以列表语法对接口进行编码

Linq 以列表语法对接口进行编码,linq,c#-4.0,interface,Linq,C# 4.0,Interface,我已将一些具体类提取到接口中 我曾经有一个名为City的类,它实现了接口 现在我试着做下面的事情 public List<ICity> Cities { get; private set; } var efCities = (from c in myentity.Cities orderby c.CityName select c); Cities = (efCities.Select(o => n

我已将一些具体类提取到接口中

我曾经有一个名为City的类,它实现了接口

现在我试着做下面的事情

public List<ICity> Cities { get; private set; }

var efCities = (from c in myentity.Cities  
                  orderby c.CityName
                  select c);

Cities = (efCities.Select(o => new City() { Id = o.Id, Country = o.Country, 
          Province = o.Province, CityName = o.CityName }).ToList());

遗憾的是,泛型类型参数与独立类型不遵循相同的类型转换规则。它们受到泛型类型所允许的内容的限制;这称为协变和逆变,在C语言中,只有数组、接口和委托可以是协变或逆变的。从C4.0开始,像List这样的具体类型不能至少为

泛型不能以您通常认为的方式工作的原因是,不可能知道泛型类型使用其类型参数做了什么;协方差是直观的,因为这就是简单赋值的工作原理,但在许多情况下,我们真正想要的是逆变换;因为编译器不能为我们做出决定,除非您另有说明,否则它默认为两者都不做

有关C4中协方差/逆变的更多信息,我建议您查看Eric Lippert的一系列文章,特别是:

以及MSDN关于它的文章:

幸运的是,在本例中有一个简单的答案,即显式IEnumerable.Cast方法:


遗憾的是,泛型类型参数与独立类型不遵循相同的类型转换规则。它们受到泛型类型所允许的内容的限制;这称为协变和逆变,在C语言中,只有数组、接口和委托可以是协变或逆变的。从C4.0开始,像List这样的具体类型不能至少为

泛型不能以您通常认为的方式工作的原因是,不可能知道泛型类型使用其类型参数做了什么;协方差是直观的,因为这就是简单赋值的工作原理,但在许多情况下,我们真正想要的是逆变换;因为编译器不能为我们做出决定,除非您另有说明,否则它默认为两者都不做

有关C4中协方差/逆变的更多信息,我建议您查看Eric Lippert的一系列文章,特别是:

以及MSDN关于它的文章:

幸运的是,在本例中有一个简单的答案,即显式IEnumerable.Cast方法:

不,列表和列表不一样。而不是指定select.toList;要访问城市,请尝试以下操作:

Cities.AddRangeefCities.Selecto=>新城市{Id=o.Id,Country=o.Country,Province=o.Province,CityName=o.CityName}

否。列表与列表不同。而不是指定select.toList;要访问城市,请尝试以下操作:

Cities.AddRangeefCities.Selecto=>新城市{Id=o.Id,Country=o.Country,Province=o.Province,CityName=o.CityName}

它与

ICity c = new City();
List和List是TechSelves类型,List不是从List派生的

向选择中添加强制转换可以解决以下问题:

Cities = (efCities.Select(o => (ICity)(new City() { Id = o.Id, Country = o.Country, 
          Province = o.Province, CityName = o.CityName })).ToList());
这与

ICity c = new City();
List和List是TechSelves类型,List不是从List派生的

向选择中添加强制转换可以解决以下问题:

Cities = (efCities.Select(o => (ICity)(new City() { Id = o.Id, Country = o.Country, 
          Province = o.Province, CityName = o.CityName })).ToList());

没有人真正说出这不起作用的原因。假设Apple和Orange都实现了IFruit:

List<Orange> oranges = new List<Orange>();
List<IFruit> fruits = oranges; // You are trying to do this, which is illegal.
                               // Suppose it were legal. Then you could do this:
fruits.Add(new Apple());

这是一种不安全的协方差。我们决定不允许对接口使用相同的危险模式;只有在编译器能够证明这样的错误是不可能的情况下,接口才能是协变的。

没有人真正说出这不起作用的原因。假设Apple和Orange都实现了IFruit:

List<Orange> oranges = new List<Orange>();
List<IFruit> fruits = oranges; // You are trying to do this, which is illegal.
                               // Suppose it were legal. Then you could do this:
fruits.Add(new Apple());

这是一种不安全的协方差。我们决定不允许对接口使用相同的危险模式;只有在编译器能够证明这种错误是不可能的情况下,接口才能是协变的。

pfft。为什么要给别人一个明确的解释和多种选择,而你可以扔掉一些东西,得到15个代表\TL;jk博士-我给了你+1。有些人只是想要答案,有些人想要解释。耸耸肩我会撤销我的回答,因为它未经测试。不要这样做。这是对的,它只是不完全是被要求的;说它不正确实在是太苛刻了。为了简洁起见,总有一些话要说:为了完整起见,可以把我的评论编辑成你的答案吗?答案正确比谁给出的更重要。为什么要给别人一个明确的解释和多种选择,而你可以扔掉一些东西,得到15个代表\TL;jk博士-我给了你+1。有些人只是想要答案,有些人想要解释。耸耸肩我会撤销我的回答,因为它未经测试。不要这样做。这是对的,它只是不完全是被要求的;说它不正确实在是太苛刻了。为了简洁起见,总有一些话要说:为了完整起见,可以把我的评论编辑成你的答案吗?有正确的答案比谁给出的更重要。仅供参考:确保你打电话给城市。如果你必须多次运行此代码,请清除,否则它将复制你的列表内容,而不是替换它们。只需 仅供参考:确保您呼叫城市。如果您必须多次运行此代码,请清除,否则它将复制您的列表内容,而不是替换它们。
Orange[] oranges = new Orange[1];
IFruit[] fruits = oranges; // dangerous, but legal!
fruits[0] = new Apple(); // legal at compile time, crashes at runtime.