В основном неуниверсальные интерфейсы были первыми, в .NET 1.0 и 1.1. Затем, когда вышел .NET 2.0, вышли общие эквиваленты. Жизнь была бы намного проще, если бы дженерики превратили ее в .NET 1.0:)
С точки зрения реализации "only" 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 (с yield return
и т. Д.), К счастью, вам редко приходится реализовывать эти вещи полностью вручную. Возможно, вам придется написать что-то похожее на приведенное выше, а затем использовать yield return
в методе GetEnumerator
.
Обратите внимание, что IList<T>
не не расширяет IList
, а ICollection<T>
делает не расширяет ICollection
. Это потому, что это менее безопасно для типов ... в то время как любой универсальный итератор может рассматриваться как неуниверсальный итератор из-за (потенциально упаковочного) преобразования любого значения в object
, IList
и ICollection
позволяют значениям быть добавленным в коллекцию; и нет смысла добавлять (скажем) строку в IList<int>
.
РЕДАКТИРОВАТЬ: Причина, по которой нам нужно IEnumerable<T>
, заключается в том, что мы можем выполнять итерации безопасным для типов способом и распространять эту информацию по всему. Если я верну вам IEnumerable<string>
, вы знаете, что можете с уверенностью предположить, что все, что будет возвращено из него, будет строковой ссылкой или нулем. С IEnumerable
нам пришлось эффективно приводить (часто неявно в операторе foreach
) каждый элемент, который был возвращен из последовательности, потому что свойство Current
IEnumerator
имеет тип object
. Что касается того, почему нам все еще нужно IEnumerable
- потому что старые интерфейсы никогда не исчезают, в основном. Там слишком много существующего кода, использующего его.
Возможно, что IEnumerable<T>
не сможет расширить IEnumerable
, но тогда любой код, желающий использовать IEnumerable<T>
, не сможет вызвать метод, принимающий IEnumerable
- и было много такие методы из .NET 1.1 и 1.0.