Создание списка с помощью перечислителя - PullRequest
0 голосов
/ 18 мая 2018

Я видел эту строку в фрагменте кода и задавался вопросом об ее использовании

var item = new List<int>.Enumerator();

Что это делает?

Ответы [ 2 ]

0 голосов
/ 18 мая 2018

Это что-то совершенно бесполезное и неправильное ...

Первый вопрос должен заключаться в том, что такое List<T>.Enumerator ... Это класс поддержки List<T>, который реализует интерфейс IEnumerator<T> (интерфейс, используемый для перечисления коллекции, например, foreach). По соображениям производительности это struct вместо class.Быть struct имеет предопределенный открытый конструктор без параметров (тот, который вы используете).У него даже есть конструктор internal с одним параметром (List<T> list), который устанавливает некоторые необходимые внутренние поля (наиболее важным является ссылка на List<>, который его создал).Этот конструктор используется List<>.GetEnumerator().

Теперь, если вы сделаете то, что написали, вы создадите «неполное» Enumerator.item.Current будет «работать» (возвращая default(T)), но если вы попытаетесь сделать item.MoveNext(), вы получите NullReferenceException.Если вы хотите IEnumerator для «пустой» коллекции, было бы лучше сделать:

var item = Enumerable.Empty<int>().GetEnumerator();

По той причине, что List<T>.Enumerator равно public вместо private или internal ... Это немного сложнее.List<T> реализует IEnumerable<T> и IEnumerable, поэтому он должен иметь как минимум два метода с этими сигнатурами:

IEnumerator<T> IEnumerable<T>.GetEnumerator()

и

IEnumerator IEnumerable.GetEnumerator()

, но по соображениям производительности он их реализуеткак явная реализация (поэтому скрывает их) и реализует третий метод:

public Enumerator GetEnumerator()

, который возвращает struct Enumerator ... теперь, благодаря тому, как работает foreach, этот третий открытый метод будетодин используется foreach.Почему это?Потому что struct, используемый через один из его интерфейсов (в данном случае IEnumerator<T> или IEnumerator), упакован (что немного замедляет его) ... но если struct используется напрямую (через * 1050)*) метод, нет бокса, а производительность немного лучше ... Программисты Microsoft дали 110% на производительности List<>: -)

0 голосов
/ 18 мая 2018

Я пошел к коду, чтобы узнать больше, вот что я нашел enter image description here

так что var item = new List<int>.Enumerator(); вернет вам экземпляр Enumerable структуры, которая будет отображатьсяв ваш список.Поскольку Enumerator является структурой, он будет инициализировать свой элемент значением по умолчанию, в этом случае на основе кода он будет инициализировать список нулем.для подробностей вы можете увидеть код списка.

В этом случае экземпляр списка не существует, поэтому при доступе к какому-либо методу, подобному этому

var item = new List<int>.Enumerator();
item.Currnet or item.MovNext()

выдает исключениев основном или по умолчанию int вы должны попробовать это.

Подробно: https://referencesource.microsoft.com/#mscorlib/system/collections/generic/list.cs

 public struct Enumerator : IEnumerator<T>, System.Collections.IEnumerator
        {
            private List<T> list;
            private int index;
            private int version;
            private T current;

            internal Enumerator(List<T> list) {
                this.list = list;
                index = 0;
                version = list._version;
                current = default(T);
            }

            public void Dispose() {
            }

            public bool MoveNext() {

                List<T> localList = list;

                if (version == localList._version && ((uint)index < (uint)localList._size)) 
                {                                                     
                    current = localList._items[index];                    
                    index++;
                    return true;
                }
                return MoveNextRare();
            }

            private bool MoveNextRare()
            {                
                if (version != list._version) {
                    ThrowHelper.ThrowInvalidOperationException(ExceptionResource.InvalidOperation_EnumFailedVersion);
                }

                index = list._size + 1;
                current = default(T);
                return false;                
            }
...