C# IEnumerable的默认具体类型是什么

C# IEnumerable的默认具体类型是什么,c#,linq,ienumerable,C#,Linq,Ienumerable,(很抱歉标题含糊不清;想不出更好的了。请随意重新措辞。) 假设我的函数或属性返回一个IEnumerable: 是否有规则控制IEnumerable是否具体化为数组、列表或其他内容 在不调用ToList()或ToArray()的情况下,将成年人投射到列表或数组是否安全 编辑 许多人花了很多精力来回答这个问题。感谢他们所有人。然而,这个问题的要点仍然没有得到回答。让我再详细说明一下: 我知道,foreach不要求目标对象是数组或列表。它甚至不需要任何形式的收藏。目标对象所需要做的就是实现枚举。但是,

(很抱歉标题含糊不清;想不出更好的了。请随意重新措辞。)

假设我的函数或属性返回一个
IEnumerable

是否有规则控制
IEnumerable
是否具体化为数组、列表或其他内容

在不调用
ToList()
ToArray()
的情况下,将
成年人
投射到
列表
或数组是否安全

编辑 许多人花了很多精力来回答这个问题。感谢他们所有人。然而,这个问题的要点仍然没有得到回答。让我再详细说明一下:

我知道,
foreach
不要求目标对象是数组或列表。它甚至不需要任何形式的收藏。目标对象所需要做的就是实现枚举。但是,如果我放置inspect目标对象的值,它将显示实际的底层对象是
List
(就像在检查装箱字符串对象时显示
object(string)
)。这就是混乱的开始。谁完成了这个物化?我检查了底层(
Where()
函数的源代码),看起来这些函数并没有这样做

所以我的问题在于两个层面

  • 第一个是纯理论的。与物理学和生物学等许多其他学科不同,在计算机科学中,我们总是精确地知道事物是如何工作的(回答@zzxyz的最后一句话);所以我试图挖掘创建
    列表
    的代理,以及它如何决定应该选择
    列表
    而不是
    数组
    ,以及是否有办法通过我们的代码影响该决定
  • 我的第二个理由是实际的。我是否可以依赖于实际底层对象的类型并将其强制转换为
    列表
    ?我需要使用一些
    列表
    功能,我想知道例如
    ((列表)成人)。BinarySearch()
    是否与
    成人一样安全。ToList().BinarySearch()

我也明白,即使我显式调用
ToList()
,它也不会造成任何性能损失。我只是想了解它是如何工作的。无论如何,再次感谢你抽出时间;我想我在这上面花的时间太多了。

任何接口都没有默认的具体类型。
接口的整个要点是保证属性、方法、事件或索引器,而不需要用户了解实现它的具体类型

在使用接口时,您所能知道的只是该接口声明的属性、方法、事件和索引器,这就是您实际需要知道的全部内容。这只是封装的另一个方面——与使用类的方法时一样,您不需要知道该方法的内部实现

在评论中回答您的问题:

如果我们没有,谁来决定具体的类型,就像我上面做的那样

这是创建实现接口的实例的代码。 因为您不能执行
var成人=new IEnumerable
——它必须是某种具体类型


就我在for linq的可枚举扩展中所看到的,
where
返回
Iterator
的实例或
WhereEnumerableIterator
的实例。我没有费心进一步检查这些类型到底是什么,但我几乎可以保证它们都实现了
IEnumerable
,或者微软的人使用了不同的c#编译器,然后我们其他人…:-)

任何接口都没有默认的具体类型。
接口的整个要点是保证属性、方法、事件或索引器,而不需要用户了解实现它的具体类型

在使用接口时,您所能知道的只是该接口声明的属性、方法、事件和索引器,这就是您实际需要知道的全部内容。这只是封装的另一个方面——与使用类的方法时一样,您不需要知道该方法的内部实现

在评论中回答您的问题:

如果我们没有,谁来决定具体的类型,就像我上面做的那样

这是创建实现接口的实例的代码。 因为您不能执行
var成人=new IEnumerable
——它必须是某种具体类型


就我在for linq的可枚举扩展中所看到的,
where
返回
Iterator
的实例或
WhereEnumerableIterator
的实例。我没有费心进一步检查这些类型到底是什么,但我几乎可以保证它们都实现了
IEnumerable
,或者微软的人使用了不同的c#编译器,然后我们其他人…:-)

一般来说,
foreach
工作所需的只是拥有一个具有可访问的
GetEnumerator()
方法的对象,该方法返回具有以下方法的对象:

void Reset()
bool MoveNext()
T Current { get; private set; } // where `T` is some type.
您甚至不需要
IEnumerable
IEnumerable

此代码在编译器计算出所需的所有内容时起作用:

void Main()
{
    foreach (var adult in new Adults())
    {
        Console.WriteLine(adult.ToString());
    }
}

public class Adult
{
    public override string ToString() => "Adult!";
}

public class Adults
{
    public class Enumerator
    {
        public Adult Current { get; private set; }
        public bool MoveNext()
        {
            if (this.Current == null)
            {
                this.Current = new Adult();
                return true;
            }
            this.Current = null;
            return false;
        }
        public void Reset() { this.Current = null; }
    }
    public Enumerator GetEnumerator() { return new Enumerator(); }
}
拥有一个适当的可枚举项可以使流程更容易、更可靠地工作。上述代码更惯用的版本是:

public class Adults
{
    private class Enumerator : IEnumerator<Adult>
    {
        public Adult Current { get; private set; }

        object IEnumerator.Current => this.Current;

        public void Dispose() { }

        public bool MoveNext()
        {
            if (this.Current == null)
            {
                this.Current = new Adult();
                return true;
            }
            this.Current = null;
            return false;
        }

        public void Reset()
        {
            this.Current = null;
        }
    }
    public IEnumerator<Adult> GetEnumerator()
    {
        return new Enumerator();
    }
}
公共班级成人
{
私有类枚举器:IEnumerator
{
公共成人当前{get;私有集;}
对象IEnumerator.Current=>this.Current;
public void Dispose(){}
公共图书馆
{
if(this.Current==null)
{
this.Current=新成人();
返回true;
}
当前=空;
返回false;
void Main()
{
    foreach (var adult in new Adults())
    {
        Console.WriteLine(adult.ToString());
    }
}

public class Adult
{
    public override string ToString() => "Adult!";
}

public class Adults
{
    public class Enumerator
    {
        public Adult Current { get; private set; }
        public bool MoveNext()
        {
            if (this.Current == null)
            {
                this.Current = new Adult();
                return true;
            }
            this.Current = null;
            return false;
        }
        public void Reset() { this.Current = null; }
    }
    public Enumerator GetEnumerator() { return new Enumerator(); }
}
public class Adults
{
    private class Enumerator : IEnumerator<Adult>
    {
        public Adult Current { get; private set; }

        object IEnumerator.Current => this.Current;

        public void Dispose() { }

        public bool MoveNext()
        {
            if (this.Current == null)
            {
                this.Current = new Adult();
                return true;
            }
            this.Current = null;
            return false;
        }

        public void Reset()
        {
            this.Current = null;
        }
    }
    public IEnumerator<Adult> GetEnumerator()
    {
        return new Enumerator();
    }
}
public class OneThroughTen : IEnumerable<int>
{
    private static int bar = 0;
    public IEnumerator<int> GetEnumerator()
    {
        while (true)
        {
            yield return ++bar;
            if (bar == 10)
                { yield break; }
        }
    }
    IEnumerator IEnumerable.GetEnumerator() { return GetEnumerator(); }
}

class Program
{
    static void Main(string[] args)
    {
        IEnumerable<int> x = new OneThroughTen();
        foreach (int i in x)
            { Console.Write("{0} ", i); }
    }
}
public IEnumerator<int> GetEnumerator()
{
  while (bar < 10)
  {
    yield return ++bar;
  }
  bar = 0;
}