C #, kodėl anoniminis metodas negali turėti derliaus ataskaitos?

Maniau, kad būtų malonu daryti kažką panašaus (su lambda grąžinimu):

 public IList<T> Find<T>(Expression<Func<T, bool>> expression) where T : class, new() { IList<T> list = GetList<T>(); var fun = expression.Compile(); var items = () => { foreach (var item in list) if (fun.Invoke(item)) yield return item; // This is not allowed by C# } return items.ToList(); } 

Tačiau sužinojau, kad negaliu naudoti pajamų anonimiškai. Įdomu, kodėl. derliaus dokumentai tiesiog sako, kad tai draudžiama.

Kadangi tai nebuvo leista, aš ką tik sukūriau sąrašą ir pridėjau elementus.

77
02 авг. Lance Fisher nustatė 02 rug. 2009-08-02 02:10 '09, 2:10 2009-08-02 02:10
@ 4 atsakymai

Ericas Lippertas neseniai parašė keletą dienoraščio pranešimų apie tai, kodėl kai kuriais atvejais pelningumas neleidžiamas.

EDIT2:

  • 7 dalis (tai buvo paskelbta vėliau ir konkrečiai išsprendžia šią problemą)

Tikriausiai rasite atsakymą ten ...


EDIT1: Tai paaiškinta 5-oje pastabose Eric, atsakant į komentarą Abhijit Patel:

Klausimas:

Eric,

Ar jūs taip pat galite suprasti, kodėl „anonimiško“ metodo ar išraiška lambda neleidžiama naudoti „derlingumo“

A:

Geras klausimas Norėčiau turėti anoniminius iteratoriaus blokus. Būtų visiškai siaubinga sukurti sau mažą sekos generatorių, kuris yra uždarytas virš vietinių kintamųjų. Priežastis, kodėl yra paprasta: nauda nėra didesnė už išlaidas. Sėkmingai sukuriant sekos generatorius vietoje iš tikrųjų yra gana mažas, kai puiki dalykų schema, o nominali metodai daugeliu scenarijų atlieka darbą gana gerai. Todėl nauda nėra tokia įtikinama.

Išlaidos yra didelės. Iteratoriaus perrašymas yra sudėtingiausias kompiliatoriaus konvertavimas, o anoniminis perrašymo metodas yra antras sunkiausias. Anoniminiai metodai gali būti kitų anoniminių metodų viduje, o anoniminiai metodai gali būti iteratoriaus blokuose. Taigi, ką mes darome, iš pradžių perrašome visus anoniminius metodus, kad jie taptų uždarymo klasės metodais. Tai antras - kompiliatorius prieš IL skleidžiant metodą. Baigus šį žingsnį, perrašymo iteratorius gali manyti, kad iteratoriaus bloke nėra anoniminių metodų; jie visi jau yra perrašyti. Todėl perrašymo iteratorius gali tiesiog sutelkti dėmesį į iteratoriaus perrašymą be to, kas galėtų būti nerealizuotas anoniminis metodas.

Be to, skirtingai nuo anoniminių metodų, iteratorius niekada nedaro lizdo. Perrašymo iteratorius gali daryti prielaidą, kad visi iteratoriaus blokai yra „aukščiausio lygio“.

Jei anoniminiai metodai gali turėti iteratoriaus blokus, tada abi šios prielaidos išeina iš >

92
02 авг. Thomas Levesque atsakymas 02 rugpjūtis 2009-08-02 02:21 '09, 2:21 am. 2009-08-02 02:21

Ericas Lippertas parašė puikią straipsnių seriją apie apribojimus (ir dizaino sprendimus, turinčius įtakos šioms galimybėms)

Dėl to jiems draudžiama bendrauti.

Aptariamas iteratoriaus blokų veikimas po gaubtu.

Kaip paprastas nesuderinamumo pavyzdys:

 public IList<T> GreaterThan<T>(T t) { IList<T> list = GetList<T>(); var items = () => { foreach (var item in list) if (fun.Invoke(item)) yield return item; // This is not allowed by C# } return items.ToList(); } 

Kompiliatorius nori konvertuoti jį į kažką panašaus:

 // inner class private class Magic { private T t; private IList<T> list; private Magic(List<T> list, T t) { this.list = list; this.t = t;} public IEnumerable<T> DoIt() { var items = () => { foreach (var item in list) if (fun.Invoke(item)) yield return item; } } } public IList<T> GreaterThan<T>(T t) { var magic = new Magic(GetList<T>(), t) var items = magic.DoIt(); return items.ToList(); } 
border=0

tuo pačiu metu iteratoriaus aspektas bando tai padaryti, kad būtų sukurta maža valstybės mašina. Kai kurie paprasti pavyzdžiai gali dirbti su sąžiningo testavimo rezultatais (pirmiausia paliečiant (galbūt atsitiktinai uždarius uždarymus), ir tada pamatysite, ar žemesnio lygio šaltinio klasės gali būti konvertuojamos į iteratorių valstybės mašinas.

Tačiau tai būtų

Gana daug darbo. Visais atvejais neįmanoma dirbti, jei bent jau iteratoriaus bloko aspektas negali užkirsti kelio uždarymo aspektui, siekiant taikyti tam tikras transformacijas, kad būtų padidintas efektyvumas (pvz., Vietinių kintamųjų skatinimas, pvz., Ne viso uždarymo klasės). Jei buvo nedidelė atsitiktinumo tikimybė, kai neįmanoma arba buvo sunku neįgyvendinti, tuomet atsirandančių paramos problemų skaičius gali būti didelis, nes daugeliui vartotojų bus prarasta nedidelė pažeidimas. Tai galima lengvai apeiti.

Savo pavyzdyje:

 public IList<T> Find<T>(Expression<Func<T, bool>> expression) where T : class, new() { return FindInner(expression).ToList(); } private IEnumerable<T> FindInner<T>(Expression<Func<T, bool>> expression) where T : class, new() { IList<T> list = GetList<T>(); var fun = expression.Compile(); foreach (var item in list) if (fun.Invoke(item)) yield return item; } 
18
02 авг. atsakymas duotas ShuggyCoUk 02 rug . 2009-08-02 02:18 '09, 2:18 am 2009-08-02 02:18

Deja, nežinau, kodėl jie to neleido, nes, žinoma, visiškai įmanoma įsivaizduoti, kaip tai veiks.

Tačiau anonimiški metodai jau yra „kompiliatoriaus magijos“ dalis, nes metodas bus išgautas į esamos klasės metodą arba net visiškai naują klasę, priklausomai nuo to, ar jis susijęs su vietiniais kintamaisiais, ar ne.

Be to, iteratorių metodai, naudojant yield taip pat įgyvendinami naudojant kompiliatoriaus magiją.

Mano spėjimas yra tai, kad vienas iš šių dviejų daro kodą neidentifikuojamą su kitu magijos gabalu, ir kad buvo nuspręsta nešvaistyti laiko atliekant šį darbą dabartinėms C # kompiliatoriaus versijoms. Žinoma, tai gali būti ne labai protingas pasirinkimas ir kad jis paprasčiausiai neveikia, nes niekas manė, kad jį įgyvendinti.

Dėl 100% tikslaus klausimo norėčiau pasiūlyti naudoti „Microsoft Connect“ svetainę ir užduoti klausimą, tikiu, kad gausite kažką naudingo.

2
02 авг. Atsakymas, kurį pateikė Lasse Vågsæther Karlsen 02 rugpjūčio 2 d. 2009-08-02 02:17 '09, 2:17 am. 2009-08-02 02:17

Norėčiau tai padaryti:

 IList<T> list = GetList<T>(); var fun = expression.Compile(); return list.Where(item => fun.Invoke(item)).ToList(); 

Žinoma, jums reikia „System.Core.dll“ failo, susijusio su „NET 3.5“ metodu „Linq“ metodui. Įjungti:

 using System.Linq; 

Sveikinimai

Tricky

1
19 сент. atsakymą pateikė Sly1024 rugsėjo 19 d 2009-09-19 23:42 '09 23:42 2009-09-19 23:42