2012-03-23 3 views
5

Во многих наших проектах я видел несколько пользовательских коллекций/классов контейнеров, которые содержат некую общую коллекцию, например. a List(of T) класс.Когда вы должны использовать IEnumerable и GetEnumerator?

Обычно они имеют метод GetXXX, который возвращает IEnumerable любого типа, который использует пользовательский класс коллекции, поэтому внутренняя коллекция может быть выполнена итерацией с использованием цикла foreach.

например.

public IEnumerable<UploadState> GetStates 
{ 
    get 
    { 
     return new List<UploadState>(m_states); 
    } 
} 

Мой вопрос заключается в том, что если эти классы вместо реализуют интерфейс IEnumerable и вызвать GetEnumerator на самом списке.

Есть ли предпочтительный способ, или это зависит от разработчика?

+1

Что такое тип m_states? Просто интересно, почему он обернут «новым списком <>» и возвращается как «IEnumerable <>» – sll

+0

http://msdn.microsoft.com/en-us/library/system.collections.ienumerable.getenumerator.aspx –

ответ

2

Если ваш класс является классом пользовательской коллекции, тогда да, он должен реализовать IEnumerable<T>. В этом случае публичное свойство для внутреннего списка будет излишним.Представьте себе простой класс:

public class People : IEnumerable<Person> 
{ 
    List<Person> persons = new List<Person>(); 

    public IEnumerator<Person> GetEnumerator() 
    { 
     return persons.GetEnumerator(); 
    } 
} 

Но если ваш класс не может действовать, как коллекции, то обеспечить общественную IEnumerable собственность для ее элементов:

public class Flight 
{ 
    List<Person> passengers = new List<Person>(); 

    public IEnumerable<Person> Passengers 
    { 
     get { return passengers; } 
    } 
} 

Во всяком случае, это всегда разработчику выбрать право дизайн.

+0

Спасибо Balazs Tihanyi, могу я задать глупый вопрос о вашем примере, почему вы внедрили IEnumerable , а не IEnumberble? Я не уверен. – bobbo

+0

Зачем вам это нужно? 'IEnumerable ' является универсальным и безопасным по типу. 'IEnumerable' для .NET 1.1 или анонимных типов. Если вы реализуете только интерфейс 'IEnumerable', вам нужно будет отображать элементы списка в их тип. –

2

Я хотел бы сделать это таким образом:

public IEnumerable<UploadState> GetStates 
{ 
    get 
    { 
     foreach (var state in m_states) { 
      yield return state; 
     } 
    } 
} 

Это чище, ваши пользователи не получают список, где они не должны (они могут привести его к List<T> после всех), и вы не» t необходимо создать объект List<T>.

EDIT: Непонятный вопрос. Я думаю, что если класс предназначен для коллекции, он должен реализовать IEnumerable<T>.

+0

Я верю здесь здесь не спрашивали, поэтому он может быть комментарием, а не ответом, но в любом случае имеет смысл с точки зрения рефакторинга – sll

0

Вы должны получать свои собственные классы сбора на основе одного из классов в пространстве имен System.Collections.ObjectModel. Они уже содержат реализации IEnumerable<T> и не общие интерфейсы IEnumerable.

1

Учтите, что в вашем примере кода создан . Я не знаю, что такое m_states, но если это коллекция типов значений, вы создаете клон исходного кода. Таким образом, возвращаемый список можно манипулировать с помощью элементов Add/Remove/Update вызывающего. без затрагивающих исходные данные.

Если m_states ссылочные типы, это по-прежнему создает новый списка, который может быть снова манипулируют вызывающую Add/Remove/Нет элементов обновления (это ссылка!), Не затрагивая исходные данные.

Как насчет IEnumerable<T>, его просто способ сделать возвращаемый тип универсальным, а не сделать прочную связь с List<T>.

+0

m_states является ссылочным типом. Его объявлено как частный Список m_states = new Список (); Я думал, что метод return не может быть обработан из-за возврата IEnumerable , а не списка ? – bobbo

+0

@bobbo: обязательно ** **, если вы выберете элемент из возвращаемой коллекции и измените его свойство, вы измените свойство ** original ** element, так как это тип * reference *. – Tigran

+0

Хорошо, это имеет смысл. Тем не менее, ваше предложение «Если m_states являются ссылочными типами, это все еще создает новый список, который может быть снова обработан элементами добавления/удаления/отсутствия вызывающего объекта (это ссылка!), Не затрагивая исходные данные». вызывает смущение. Вы имеете в виду, что новый возвращаемый список может быть добавлен, и элементы могут быть удалены, но нет обновлений? Я думал, что, поскольку он вернулся ienumerable, вы можете изменить элементы в списке, т. Е. Изменить свойство, как вы сказали, но вы не можете добавлять и удалять элементы в списке. Это верно? – bobbo

0

Я думаю, что если ваш недавно реализованный класс просто ведет себя так, как это делает список, нет необходимости его реализовывать. Если вам нужна какая-то пользовательская логика, это зависит от того, что вы хотите сделать; вы можете наследовать список или вы можете реализовать IEnumerable. Это просто зависит от того, что должно быть достигнуто.

Смежные вопросы