IEnumerable
和IEnumerable<T>
之间有什么区别?
我已经看到很多框架类实现了这两个接口,因此我想知道通过实现它们可以获得哪些优势?
请看看它们是如何定义的:
public interface IEnumerable
{
[DispId(-4)]
IEnumerator GetEnumerator();
}
public interface IEnumerable<T> : IEnumerable
{
IEnumerator<T> GetEnumerator();
}
正如我们所见,IEnumerable<T>
来自IEnumerable
,这意味着IEnumerable
所拥有的,IEnumerable<T>
继承,那么为什么我们实现两者而不仅仅IEnumerable<T>
}?实施IEnumerable<T>
还不够吗?
同样,还有其他类似的对:
IList
和IList<T>
ICollection
和ICollection<T>
我也想知道这些。
答案 0 :(得分:55)
基本上,非通用接口首先出现在.NET 1.0和1.1中。然后,当.NET 2.0问世时,通用的等价物就出现了。如果泛型已经进入.NET 1.0,那么生活将变得更加简单:)
在实现“仅”IEnumerable<T>
而不是两者中 - 你基本上有来实现它们,并且你必须使用显式接口实现,因为它们都定义了无参数{ {1}}方法。由于GetEnumerator
也延伸IEnumerator<T>
,它通常是这样的:
IEnumerator
另一方面,使用C#2中引入的迭代器块(带public IEnumerator<T> GetEnumerator()
{
// Return real iterator
}
// Explicit implementation of nongeneric interface
IEnumerator IEnumerable.GetEnumerator()
{
// Delegate to the generic implementation
return GetEnumerator();
}
等),幸运的是,你很少需要完全手工实现这些东西。您可能需要编写类似上面的内容,然后在yield return
方法中使用yield return
。
请注意,GetEnumerator
不延伸IList<T>
,而IList
<{1}}。这是因为它的类型安全性较低......而任何泛型迭代器都可以被视为非泛型迭代器,因为任何值(ICollection<T>
,ICollection
和{{的(可能是装箱)转换1}}允许将值添加到集合中;将(比方说)字符串添加到object
。
编辑:我们需要IList
的原因是我们可以以类型安全的方式进行迭代,并传播该信息。如果我向您返回ICollection
,您就知道您可以安全地假设从它返回的所有内容都是字符串引用或null。使用IList<int>
,我们必须有效地(通常隐式地在IEnumerable<T>
语句中)强制转换从序列返回的每个元素,因为IEnumerable<string>
的{{1}}属性只是输入IEnumerable
。至于为什么我们仍然需要foreach
- 因为旧接口永远不会消失。使用它的现有代码太多了。
Current
可能无法扩展IEnumerator
,但是任何想要使用object
的代码都无法调用接受IEnumerable
的方法 - 并且有许多类似于.NET 1.1和1.0的方法。
答案 1 :(得分:7)
一个返回Object类型的对象,另一个返回类型为T的对象。
答案 2 :(得分:2)
至于为什么你看到定义两者的类,尽管IEnumerable&lt; T>实现IEnumerable,它不是必需的,但在自我记录中有时列出子接口是很好的。考虑
interface IA { }
interface IB : IA { }
class A : IB {} // legal, IB implements IA
class B : IA, IB {} // also legal, possible more clear on intent
答案 3 :(得分:1)
在遍历循环时,IEnumerator维持状态。 它会记住光标位置而IEnumerable没有。