为什么IEnumerable<;T>;只有「;“出去”;协变标志和非;在;c#?
我想知道,为什么为什么IEnumerable<;T>;只有「;“出去”;协变标志和非;在;c#?,c#,.net,.net-4.0,ienumerable,covariance,C#,.net,.net 4.0,Ienumerable,Covariance,我想知道,为什么IEnumerable只有out而没有in逆变标志 public interface IEnumerable<out T> 对象大于字符串,因此编译器担心我们会执行以下操作: objects = objects.First().Select(x=>5);// ( we cant insert int to string...) 很好,理解 但是如果我想将IEnumerable用作插入,该怎么办 比如: IEnumerable<object> o
IEnumerable
只有out
而没有in
逆变标志
public interface IEnumerable<out T>
对象
大于字符串
,因此编译器担心我们会执行以下操作:
objects = objects.First().Select(x=>5);// ( we cant insert int to string...)
很好,理解
但是如果我想将IEnumerable用作插入,该怎么办
比如:
IEnumerable<object> objects = ...;
IEnumerable<string> strings = objects
IEnumerable对象=。。。;
IEnumerable字符串=对象
所以我也可以插入到对象中
但问题是没有IEnumerable
我在这里遗漏了什么吗?我认为这与键入safity密切相关:如果您在列表中怎么办
IEnumerable{“Hello”,2.34d,新的MyColObject(),enumvalue}
运行时应该如何处理这些转换
在string
的情况下,这可能是一个简单的情况,因为调用ToString()
的覆盖(如果有)应该足够了,但框架设计器不能依赖于自定义情况,应该提供通用解决方案
希望这能有所帮助。您不能插入到
IEnumerable
中。不幸的是,没有“可插入的”
没有界面告诉您只能将项目添加到集合中。这将是通用类型中的。因为您可以在每个集合接口上获取项,所以在
通用参数中不可能有
编辑
接口IEnumerable
只有getter,因此不能使用该接口向集合插入任何元素。因此,IEnumerable
的声明中允许out
。它告诉编译器,类型为T
的值只朝一个方向移动,即“出来”。这使得它在一个方向上兼容。您可以将IEnumerable
用作IEnumerable
,因为您仅从中读取。可以将字符串作为对象读取。但是你不能写入它,不能将对象作为字符串传递。它可能是一个整数或任何其他类型。Eric Lippert在C#中引入协方差/反方差之前,对这一点有自己的见解,值得一读
一个简单的例子是
public class Animal(){
...
}
public class Giraf(){
public void LookAboveTheClouds(){}
}
IEnumerable<Animal> animals = new list<Animal>{
new Elephant(),
new Tiger(),
new TinyMouse()};
IEnumerable<Giraf> girafs = animals;
foreach(var giraf in girafs){
//elephants,tigers and tiny mice does not suuport this
giraf.LookAboveTheClouds()
}
公共类动物(){
...
}
公共级Giraf(){
public void lookovertheclouds(){}
}
IEnumerable动物=新列表{
新象(),
新老虎(),
新TinyMouse()};
IEnumerable girafs=动物;
foreach(girafs中的var giraf){
//大象、老虎和小老鼠并不支持这一点
giraf.lookovertheclouds()
}
换句话说,编译器无法保证您可以安全地将IEnumerable
用作IEnumerable
。所有的女孩都是动物,但不是所有的动物都是女孩我看不出你的问题。当使用IEnumerable
时,您不能插入,这不是您要做的。您试图做的是将IEnumerable
的值赋值为IEnumerable
,但这不起作用。当为IEnumerable
分配类型为IEnumerble
的对象时,不能保证列表中的所有对象都是字符串类型。这就是为什么我们不能那样做
协变,out
关键字,接口确保消费部分始终能够理解输出,即,可以将IEnumerable
转换为IEnumerable
列表,因为string:object
和使用object
列表的人必须知道如何处理string
相反,接口中的关键字使您能够将对象强制转换为指定较少的泛型,也就是说,IComparer
可以强制转换为IComparer
,因为实现IComparer
的类现在必须如何处理string
,因为它是相反的
请在此处阅读更多信息:如评论中所述,您不能使用IEnumerable修改集合
static void Main(string[] args)
{
IList<string> strings = new List<string> { "a", "b", "c" };
IList<object> objects = strings; ** // This will give an error because compiler does not want you to do the line below **
objects.Add(5); // Type safety violated for IList<string> hence not allowed
// The code below works fine as you cannot modify the strings collection using IEnumerable of object
//IEnumerable<string> strings = new List<string> { "a", "b", "c" };
//IEnumerable<object> objects = strings;
}
由于您提到的类型安全问题(将int插入字符串列表),编译器将不允许使用下面的代码,因为您可以使用对象修改这里的字符串列表
IEnumerable只是集合上的迭代器
static void Main(string[] args)
{
IList<string> strings = new List<string> { "a", "b", "c" };
IList<object> objects = strings; ** // This will give an error because compiler does not want you to do the line below **
objects.Add(5); // Type safety violated for IList<string> hence not allowed
// The code below works fine as you cannot modify the strings collection using IEnumerable of object
//IEnumerable<string> strings = new List<string> { "a", "b", "c" };
//IEnumerable<object> objects = strings;
}
static void Main(字符串[]args)
{
IList strings=新列表{“a”、“b”、“c”};
IList objects=strings;**//这将给出一个错误,因为编译器不希望您执行下面的行**
objects.Add(5);//IList违反了类型安全性,因此不允许
//下面的代码工作正常,因为无法使用对象的IEnumerable修改字符串集合
//IEnumerable strings=新列表{“a”、“b”、“c”};
//IEnumerable对象=字符串;
}
希望这有帮助。您不能将IEnumerable
分配给IEnumerable
,因为它可能包含非子项的元素
但是,如果我想使用IEnumerable作为插入,该怎么办?比如:
顺便说一句,你可能想看看标签。@downvoter,请解释一下。你说的“插入对象”是什么意思?你不能插入IEnumerable
,我在你的问题中看不到任何插入?你真正的问题是什么?@tomasjanson我希望能够在对象中插入字符串值。但是Ienumerable在
中没有,它几乎是一样的Iernumerable@Royi:我的问题是:如何通过IEnumerable插入?那么你告诉我的是我不能使用IEnumerable类型?那么strings=strings呢。选择(x=>“myInsertedString”)
?
IEnumerable<object> objects = ...;
IEnumerable<string> strings = objects
IEnumerable<string> strings = objects.Cast<string>();