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;
}