58

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>还不够吗?

同样,还有其他类似的对:

  • IListIList<T>
  • ICollectionICollection<T>

我也想知道这些。

4

4 回答 4

67

基本上,非泛型接口首先出现在 .NET 1.0 和 1.1 中。然后当 .NET 2.0 出现时,通用的等价物也出现了。如果泛型进入 .NET 1.0,生活会简单得多 :)

就实现“仅”IEnumerable<T>而不是两者而​​言 - 您基本上必须同时实现两者,并且您也必须使用显式接口实现,因为两者都定义了无参数GetEnumerator方法。作为IEnumerator<T>扩展IEnumerator,它通常是这样的:

public IEnumerator<T> GetEnumerator()
{
    // Return real iterator
}

// Explicit implementation of nongeneric interface
IEnumerator IEnumerable.GetEnumerator()
{
    // Delegate to the generic implementation
    return GetEnumerator();
}

另一方面,幸运的是,使用 C# 2(with yield returnetc)中引入的迭代器块,您很少需要完全手动实现这些东西。您可能需要编写类似上面的内容,然后yield returnGetEnumerator方法中使用。

注意IList<T>不扩展,也不扩展。_ _ 那是因为这样做的类型安全性较低……而任何泛型迭代器都可以被视为非泛型迭代器,因为任何值都(可能装箱)转换为,并允许将值添加到集合中;并且将字符串添加(例如)到.IListICollection<T>ICollectionobjectIListICollectionIList<int>

编辑:我们需要的原因IEnumerable<T>是我们可以以类型安全的方式进行迭代,并传播该信息。如果我返回一个IEnumerable<string>给你,你知道你可以安全地假设从它返回的所有内容都是一个字符串引用或空值。使用IEnumerable,我们必须有效地转换(通常在foreach语句中隐式地)从序列返回的每个元素,因为 的Current属性IEnumerator只是 type object。至于为什么我们仍然需要IEnumerable- 因为旧接口基本上永远不会消失。使用它的现有代码太多。

IEnumerable<T>不扩展是可能的IEnumerable,但是任何想要使用 an 的代码IEnumerable<T>都无法调用接受的方法IEnumerable- 并且有很多类似的方法来自 .NET 1.1 和 1.0。

于 2011-02-11T17:34:37.677 回答
10

一个返回 Object 类型的对象,另一个返回 T 类型的对象。

于 2011-02-11T17:34:59.687 回答
3

至于为什么您会看到定义这两者的类,尽管 IEnumerable<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
于 2011-02-11T17:40:29.983 回答
0

在循环中迭代时,IEnumerator 保持状态。它会记住光标位置,而 IEnumerable 不会。

于 2013-02-24T22:55:21.157 回答