1. Funktiot, jotka toteutetaan yield-menetelmällä
Tuoton tuotto:
Tarkastellaan seuraavaa koodia, joka toteuttaa funktion, joka muistuttaa taulukon läpikäymistä foreach yield returnin kautta, mikä osoittaa, että yield returnia käytetään myös iteraattorin funktion toteuttamiseen.
Yield break:
Alla olevaa koodia katsoessa vain 1 ja 2 ovat lähtöpisteitä, mutta eivät 3, mikä tarkoittaa, että iteraattori pysäytettiin yield breakin yhteydessä, joten yieldbreakia käytetään iteroinnin lopettamiseen.
2. Sitä voidaan käyttää vain <T><T>metodeissa, operaattoreissa ja accessor-tiedostoissa, jotka palauttavat IEnumerable, IEnumerable, IEnumerator tai IEnumerator.
3. Yield-avainsanan toteutusperiaate
Korvasimme foreach -silmukan while-silmukassa ja huomasimme, että vaikka emme toteuttaneet GetEnumerator(), emmekä toteuttaneet vastaavia IEnumeratorin MoveNext() ja Current-ominaisuuksia, työskentelimme silti näiden funktioiden kanssa.
Miksi näin on, voimme käyttää ILSpyä dekompoiraamaan generoidun exe:n ja löytääksemme syyn.
Koska suora dekompilaatio C#:ksi muuttuu sellaiseksi kuin se on
Siksi päätimme purkaa sen IL-koodiin C#-merkinnöillä, vaikka luettavuus on heikko, mutta voimme ymmärtää periaatteet yksityiskohtaisesti. Katsotaanpa ensin ohjelman käännöstä, uusi luokka generoidaan automaattisesti käännöksen aikana.
Katsotaanpa koodia tarkemmin, ja EnumerableFuc() palauttaa tämän uuden luokan.
Kun tarkastelemme luokan toteutusta, jonka tämä koodi tuottaa automaattisesti, näemme, että se perii IEnumerable<T>-, IEnumerable-, IEnumerator- tai IEnumerator-ominaisuudet, ja meidän <T>pitäisi arvata, että tämä uusi luokka on syy siihen, miksi emme toteuta vastaavia IEnumeratorin MoveNext()- ja Current-ominaisuuksia, mutta voimme silti käyttää näitä funktioita normaalisti.
Katsotaanpa, miten tämä luokka iteroidaan, tarkastellaan pääasiassa MoveNext()-funktiota
Jokainen kutsu MoveNext()-funktiolle lisää tilaan 1, ja yhteensä tehdään 4 iteraatiota, joista kolme ensimmäistä palautetaan tosi ja viimeinen epätosi, mikä tarkoittaa iteroinnin päättymistä. Nämä neljä iteraatiota vastaavat enumberableFuc():n lauseita, jotka on jaettu neljään osaan kolmella yield return -lauseella.
Todellinen prosessi iterointiprosessissa enumberableFuc():lla on:
1. Suorita enumberableFuc()-funktio, jotta koodi generoi automaattisesti luoman luokan. 2. Kutsu sitten GetEnumberator()-funktio aloittaaksesi iteraation itse hankitulla luokalla iteraattorina. 3. Joka kerta kun suoritat MoveNext():n, tila kasvaa yhdellä, ja switch-lause mahdollistaa koodin eri osien suorittamisen aina, kun kutsut MoveNext():tä. 4。 MoveNext() palauttaa epätosi, päättyy. Tämä osoittaa myös, että yield-avainsana on itse asiassa syntaktinen sokeri, ja se on lopulta iteratiivinen funktio, joka toteutetaan IEnumberable<T>-, IEnumberable-, <T>IEnumberator- ja IEnumberator-rajapintojen avulla.
|