为什么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>();