1. Функции, реализирани чрез yield
Доходна възвръщаемост:
Нека разгледаме следния код, който реализира функция, подобна на преминаване през масив с foreach чрез yield return, което показва, че yield return се използва и за реализиране на функцията на итератора.
Прекъсване на добив:
Гледайки кода по-долу, само 1 и 2 са изход, но не и 3, което показва, че итераторът е бил спрян от прекъсване на yield, затова се използва прекъсване на yield за прекратяване на итерацията.
2. Може да се използва само в <T><T>методи, оператори, получаващи аксесори, които трябва да върнат IEnumerable, IEnumerable, IEnumerator или IEnumerator.
3. Принципът на имплементацията на ключовата дума yield
Заменихме foreach loop с while loop и установихме, че въпреки че не реализирахме GetEnumerator(), нито пък приложихме съответните свойства MoveNext() и Current на IEnumerator, все пак работим с тези функции.
Що се отнася до причината за това, можем да използваме ILSpy, за да декомпилираме генерирания exe файл и да намерим причината.
Тъй като директната декомпилация към C# ще стане такова, каквото е
Затова решихме да го декомпилираме в IL код с C# анотации, макар четивността да е слаба, но можем да разберем принципите в детайли. Нека първо разгледаме превода на програмата – нов клас се генерира автоматично по време на компилацията.
Нека разгледаме кода по-отблизо и EnumerableFuc() връща този нов клас.
Ако разгледаме имплементацията на класа, който този код генерира автоматично, можем да видим, че той наследява <T>IEnumerable, IEnumerable, IEnumerator или IEnumerator, и <T>би трябвало да можем да предположим, че този нов клас е причината да не реализираме съответните MoveNext() и Current свойства на IEnumerator, но все пак можем да използваме тези функции нормално.
Нека разгледаме как този клас се итерира, нека основно разгледаме функцията MoveNext()
Всяко извикване на функцията MoveNext() добавя 1 към състоянието и се правят общо 4 итерации, като първите три връщат true, а последната връща false, което означава край на итерацията. Тези четири итерации съответстват на операторите в enumberableFuc(), които са разделени на 4 части по 3 и дават възвръщаемост на изказвания.
Реалният процес на итерация с enumerableFuc() е:
1. Изпълнете функцията enumberableFuc(), за да получите екземпляр на класа, автоматично генериран от кода. 2. След това извикайте функцията GetEnumberator(), за да започне итерация върху самия придобит клас като итератор. 3. Всеки път, когато стартирате MoveNext(), състоянието се увеличава с 1, а операторът switch ви позволява да изпълнявате различни части от кода всеки път, когато извикате MoveNext(). 4。 MoveNext() връща false, край. Това също показва, че ключовата дума yield всъщност е синтактичен захар и в крайна сметка е итеративна функция, реализирана чрез <T>имплементиране на интерфейси IEnumerable, IEnumerable, <T>IEnumberator и IEnumberator.
|