Разница между IEnumerable и IEnumerable?
в чем разница между IEnumerable
и IEnumerable<T>
?
Я видел много классов framework, реализующих оба этих интерфейса, поэтому я хотел бы знать, какие преимущества можно получить, реализуя оба?
пожалуйста, посмотрите, как они были определены:
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>
Я хотел бы знать о них.
4 ответов
в основном неуниверсальные интерфейсы, в .Чистая 1.0 и 1.1. Затем, когда .NET 2.0 вышел, вышли общие эквиваленты. Жизнь была бы намного проще, если бы дженерики сделали это в .NET 1.0:)
С точки зрения реализации "только"IEnumerable<T>
вместо обоих - в основном есть для реализации, и вы должны использовать явную реализацию интерфейса, учитывая, что оба определения параметров GetEnumerator
метод. As 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
etc) вам редко нужно осуществлять эти вещи полностью вручную, к счастью. Возможно, вам придется написать что-то подобное выше, а затем использовать yield return
на GetEnumerator
метод.
отметим, что IList<T>
тут не расширения IList
и ICollection<T>
тут не расширения ICollection
. Это потому, что это менее безопасно для типа так поступать... в то время как любой универсальный итератор можно рассматривать как неуниверсальные итератор из-за (потенциально бокс) преобразования любого значения!--12-->, IList
и ICollection
разрешить значения добавил в коллекцию; и нет смысла добавлять (скажем) строку в IList<int>
.
EDIT: причина, по которой нам нужно IEnumerable<T>
Так, что мы можем итерировать безопасным для типа способом и распространять эту информацию. Если я верну IEnumerable<string>
- вы знаете, что вы можете спокойно предположим, все вернулись из него будет ссылка строки или null. С IEnumerable
, мы должны эффективно бросить (часто неявно в foreach
оператор) каждый элемент, который был возвращен из последовательности, потому что Current
собственность IEnumerator
просто типа object
. Что касается того, почему мы еще нужно IEnumerable
- потому что старые интерфейсы не уходят, в основном. Слишком много существующего кода использует его.
это было бы возможно для IEnumerable<T>
не продлевать IEnumerable
, но тогда любой код, желающий использовать IEnumerable<T>
не удалось вызвать метод, принимающий IEnumerable
- и было много таких методов, как .NET 1.1 и 1.0.
Что касается того, почему вы видите классы, определяющие оба, достаточно, хотя IEnumerable реализует IEnumerable, его не нужно, но хорошо в самодокументировании, чтобы иногда перечислять подинтерфейсы. Считать
interface IA { }
interface IB : IA { }
class A : IB {} // legal, IB implements IA
class B : IA, IB {} // also legal, possible more clear on intent
при итерации по циклу IEnumerator поддерживает состояние. Он запоминает положение курсора, а IEnumerable-нет.