为什么IEnumerable<;T>;在C#4中变为协变?
在早期版本的C#为什么IEnumerable<;T>;在C#4中变为协变?,c#,generics,ienumerable,language-design,covariance,C#,Generics,Ienumerable,Language Design,Covariance,在早期版本的C#IEnumerable中定义如下: public interface IEnumerable<T> : IEnumerable 公共接口IEnumerable:IEnumerable 由于C#4,定义为: public interface IEnumerable<out T> : IEnumerable 公共接口IEnumerable:IEnumerable 这只是为了让LINQ表达式中令人讨厌的角色消失吗 这不也会带来同样的问题吗,比如按顺序使
IEnumerable
中定义如下:
public interface IEnumerable<T> : IEnumerable
公共接口IEnumerable:IEnumerable
由于C#4,定义为:
public interface IEnumerable<out T> : IEnumerable
公共接口IEnumerable:IEnumerable
- 这只是为了让LINQ表达式中令人讨厌的角色消失吗
- 这不也会带来同样的问题吗,比如按顺序使用
string[]: 这只是为了让LINQ表达式中令人讨厌的角色消失吗 它使事情表现得像人们通常期望的那样;p 这不会带来与
string[]相同的问题吗 这只是为了让LINQ表达式中令人讨厌的角色消失吗 不仅是在使用LINQ时。它在任何有
且代码需要IEnumerable
的地方都很有用IEnumerable
这难道不会带来与
相同的问题吗?Marc和CodeInChaos的答案很好,但只需补充一些细节: 首先,听起来您有兴趣了解我们制作此功能所经历的设计过程。如果是这样的话,那么我鼓励您阅读我在设计和实现该功能时撰写的一系列长篇文章。从页面底部开始: 这只是为了让LINQ表达式中令人讨厌的角色消失吗 不,这不仅仅是为了避免使用string[]
表达式,而是鼓励我们使用此功能的动机之一。我们意识到,“为什么我不能用一个长颈鹿序列来处理一系列动物?”问题的数量会上升,因为LINQ鼓励使用序列类型。我们知道我们想先给Cast
添加协方差 实际上,我们甚至在C#3中也考虑过将IEnumerable
设置为协变,但我们认为,如果不将整个特性介绍给任何人使用,那么这样做会很奇怪IEnumerable
这会不会带来与
中的string[]相同的问题,因此C#编译器会严格检查C#中的方差注释(与数组不同)?@soc yes;在定义协变或逆变接口/委托时,以及在使用协变分配引用时(例如,将
分配给IEnumerable
)。如果您将IEnumerable
,则只能有返回此类信息的API;相反地,添加到
。因此,属性/索引器不能同时具有该类型的
和get
,set
/ref
,很明显,返回类型和参数类型都被检查了。考虑到一个稍微相关的问题的答案,我想知道这是如何工作的:从那以后,是否有任何变化允许MS改变方差?@soc-什么都没有;请注意,只有out
提供此功能-在IEnumerable
或IList
上没有差异,因为它们不兼容;它们有“in”和“out”两种用法,因此既不是协变的也不是逆变的。@在您的示例中,您正在实现接口-您没有ICollection
,只是out
。另外,:IEnumerable
不适用于类-仅适用于接口和委托/。嘿,感谢您抽出时间!是的,我对设计过程很感兴趣。我想知道的一件事是,不支持协变返回类型和C#/CLR中的“真实”(抱歉)差异对其他语言有多大影响。例如。今天有一篇关于Scala.NET的帖子。我想知道他们对这两个问题做了什么。。。(@soc:几乎每当有人在评论中提出一个非琐碎的问题时,打开一个新的问题是一个好主意。我当然不是Scala或C++/CLI方面的专家,我相信这两个方面都有返回类型协方差,即使CLR本机不支持它。@Eric Lippert:出于好奇,是否有可能vb/c#/.net的未来版本要么允许实现读/写属性的类隐式地被视为具有只读和只读实现,要么允许在协变/逆变接口中使用读写属性,将其标记为只读或只读?在许多情况下,它将用于ul允许IList从协变IReadableList派生,前提是不需要IList的实现添加只读属性。@supercat:任何事情都有可能。我们当然注意到,在类型系统中,我们没有很好的支持来推理类类型的不变性,许多人建议“只读列表”和“只读数组”当协变使用时,类型会更安全。但是我们目前没有针对特定功能的具体计划来解决这些问题;我们只是知道很多人都有这些问题。@Eric Lippert:我不是在考虑不可变的类型,而是现有类型的只读接口(尽管从IReadableList派生的IImmutableList也很有用)。假设我需要一个有效的方法以相反的顺序对IEnumerable中的项进行操作。可以枚举到列表,但如果该项已经是IList,则效率低下。如果我需要一个IEnumerable,但得到了一个列表,有没有办法利用它是IList的事实?如果IList继承了IReadableList,这很容易。理想情况下,将IEnumerable作为IEnumerable传递就像将其作为IEnumerable传递一样,但这并不总是实用的。除非使用反射,例如,否则很难编写“计数”方法,将ICollection作为IEnumerable给定,可以利用ICollection.Count。有人可能会说ICollection的设计很差,但我认为ICollection的设计者没有任何理由out
void DoSomething(IEnumerabe<Base> bla); void DoSomething(object blub); IEnumerable<Derived> values = ...; DoSomething(values);
if (x is IEnumerable<Animal>) ABC(); else if (x is IEnumerable<Turtle>) DEF();
class B { public void M(IEnumerable<Turtle> turtles){} } class D : B { public void M(IEnumerable<Animal> animals){} }
class Weird : IEnumerable<Turtle>, IEnumerable<Banana> { ... } class B { public void M(IEnumerable<Banana> bananas) {} } class D : B { public void M(IEnumerable<Animal> animals) {} public void M(IEnumerable<Fruit> fruits) {} }