.NET 4.5To nye samlingsgrensesnitt, IReadOnlyList og IReadOnlyDictionary, har blitt lagt til. Selv om disse grensesnittene kan virke så hverdagslige på overflaten, avslører de ganske komplekse historier om bakoverkompatibilitet, interoperabilitet og rollen til ko-mutabilitet.
IReadOnlyList og IReadOnlyDictionary er to grensesnitt som .NET-utviklere alltid har ønsket å ha. I tillegg til å gi en viss følelse av symmetri (i motsetning til skrivbare grensesnitt), bør et skrivebeskyttet grensesnitt eliminere implementeringen av metoder som bare kaster et NotSupportedException-unntak og ikke gjør noe. Alt dette ble ikke fullført på grunn av tidsbegrensninger.
Neste mulighet er inne. NETTO 2,0. Dette gjør det mulig for Microsoft å pensjonere svakt typede samlinger og erstatte dem med sterkt typede peer-samlinger. Imidlertid gikk basebiblioteket[1]-teamet nok en gang glipp av muligheten til å lage en lesebeskyttet liste, som Kit George skrev,
Siden vi har til hensikt å tilby en standardimplementering for problemet du snakker om med Joe, i stedet for å gi et grensesnitt, tilbyr vi ReadOnlyCollectionBase-baseklassen. Men jeg kan forstå hvorfor folk er tilbakeholdne med å bruke det, fordi det ikke er en sterk type. Men med introduksjonen av generiske produkter har vi nå også ReadOnlyCollection<T>, slik at du ikke bare får samme funksjonalitet, men også en sterk type: flott!
Siden ReadOnlyCollection <T>ikke er en lukket klasse, kan du skrive din egen samling i full fart om nødvendig. Fordi disse samlingene vi har laget for dette er tilpasningsdyktige til generelle behov, planlegger vi ikke å introdusere grensesnitt for dette samme konseptet. Krzysztof Cwalina uttrykte også sin mening om dette temaet,
Enten dette høres overraskende ut eller ikke, er IList og IList <T>de to grensesnittene vi har til hensikt å bruke for skrivebeskyttede samlinger. Begge har IsReadOnly boolsk egenskap, som skal returnere true når en skrivebeskyttet samling implementerer denne egenskapen. Grunnen til at vi ikke ønsker å legge til et rent skrivebeskyttet grensesnitt, er at vi føler det tilfører for mye unødvendig kompleksitet til grunnbiblioteket. Merk at når det gjelder kompleksitet, refererer vi både til dette nye grensesnittet og dets brukere.
Vi mener at hvis API-designeren ikke bryr seg om å sjekke IsReadOnly-egenskapen under kjøring og hvilke unntak den kan kaste, så er det greit å bruke IList-grensesnittet i dette tilfellet; Hvis de er villige til å tilby et veldig rent, tilpasset API på én gang, bør de i dette tilfellet vise implementeringen av IList-grensesnittet og publisere et skreddersydd skrivebeskyttet API. Det siste er typisk for samlinger eksponert fra objektmodellen. Selv om utviklere har klaget på denne situasjonen, veier de nye mulighetene generiske spill gir langt tyngre enn dette kjernepunktet, og problemet ligger i . NET 4 ble stort sett ignorert tidligere. Denne avgjørelsen utløste imidlertid også noen reaksjoner, som vi skal diskutere senere.
Med inn. En spennende ny funksjon i .NET 4 har blitt lagt til i spilletiden. I en tidligere versjon. .NET, når grensesnitt blir typer, er disse grensesnittene altfor begrenset. For eksempel, selv om Kunde arver fra Person, er det ikke mulig å sende et objekt av typen IEnumerable <Customer>som parameter til en funksjon av typen IEnumerable<Person>. Med tillegg av kovariant støtte ble denne begrensningen delvis opphevet.
Vi sier «delvis» fordi folk i noen tilfeller bør bruke et grensesnitt med et rikt API samtidig, i stedet for å bruke et IEnumerable-grensesnitt. Selv om IList-grensesnittet ikke er kovariant, bør et skrivebeskyttet listegrensesnitt være det. Dessverre, . .NETs basebiblioteksteam har igjen besluttet å ikke ta tak i denne forsømmelsen.
Så endret introduksjonen av WinRT og COMs comeback alt. COM-interoperabilitet var en gang en teknologi utviklere brukte når de ikke hadde noe annet valg, men det har blitt en . Hjørnesteinen i .NET-programmering. Og siden WinRT eksponerer IVectorView <T>og IMapView<K, V> grensesnittene, derfor. .NET må også justeres deretter.
En interessant funksjon ved WinRT-programmet er kunngjøringen av forskjellige, men lignende API-er for hver utviklingsplattform. Som du kanskje allerede vet, er alle metodenavn representert av camelCased [2], mens C++- og .NET-utviklere ser metodenavn som PascalCased [3]. En annen mer drastisk endring er den automatiske kartleggingen mellom C++- og .NET-grensesnittene. Derfor. .NET-utviklere trenger ikke å håndtere Windows.Foundation.Collections-navnerommet, bare fortsette å bruke System.Collections.Generic-navnerommet. IVectorView<T>- og IMapView<K, V>-grensesnittene vil bli konvertert av kjøretiden til henholdsvis IReadOnlyList-grensesnitt <T>og IReadOnlyDictionary<TKey, TValue>-grensesnitt.
Det er verdt å merke seg at disse grensesnittnavnene i C++/WinRT til en viss grad er mer nøyaktige. Disse grensesnittene brukes til å representere noen visninger av en samling, men grensesnittet sikrer ikke at selve samlingen er uforanderlig. Selv blant de med erfaring. En vanlig feil blant .NET-utviklere er å anta at ReadOnlyCollection-typen er en kopi av en uforanderlig samling, men i realiteten er det bare en wrapper for en aktiv samling (se Andrew Arnotts innlegg med samme navn for mer informasjon om skrivebeskyttet, frosne og uforanderlige samlinger).
Selv om <T>IList-grensesnittet har alle de samme medlemmene som IReadOnlyList-grensesnittet<T>, og alle IList-typer <T>kan representeres som skrivebeskyttede lister, <T>arver ikke IList fra IReadOnlyList<T>, noe som kan være interessant å lære om. Immo Landwerth forklarte,
Grunnen til at det fungerer er at disse skrivebeskyttede grensesnittene er rene delmengder av lese-skrivegrensesnitt, noe som virker som en rimelig antakelse. Dessverre stemmer ikke denne antakelsen overens med virkeligheten, siden hver metode på hvert grensesnitt på metadata-nivå har sin egen plass (noe som gjør eksplisitte grensesnittimplementasjoner funksjonelle). Eller med andre ord, den eneste muligheten til å introdusere et skrivebeskyttet grensesnitt som en variabel klassebaseklasse er å falle tilbake til . NET 2.0, altså når de opprinnelig ble unnfanget. Når den er helt utrullet, er den eneste endringen å legge til kovariante og/eller invertermarkører (representert som "inn" og "ut" i VB og C#).
Da jeg ble spurt hvorfor det ikke finnes noe IReadOnlyCollection-grensesnitt<T>, svarte Immo,
Vi vurderte dette designet, men vi følte at det å legge til en type som kun ga Count-attributtet ikke ville tilføre mye verdi til grunnbiblioteket. I basisbiblioteksteamet mener vi at hvis et API starter på minus 1000, er det ikke nok til å tilføre noe verdi til å rettferdiggjøre at det legges til. Begrunnelsen for å legge til nye API-er inkluderer også en kostnad, for eksempel vil utviklere ha flere konsepter å velge mellom. Først trodde vi at å legge til denne typen ville gjøre koden bedre i visse situasjoner hvor man bare vil få en telling og så gjøre noe interessant med den. For eksempel, legg til en eksisterende samling i bulk. Men i disse tilfellene har vi oppmuntret folk til kun å bruke IEtallable-grensesnittet<T>, og <T>for det spesielle tilfellet at det finnes en instans som implementerer ICollection-grensesnittet. Siden alle våre innebygde samlingstyper implementerte dette grensesnittet, har det ikke vært noen ytelsesforbedring i de vanligste situasjonene. Forresten, <T>utvidelsesmetoden Count() for IEnumerable kan også gjøre dette. Disse nye grensesnittene er tilgjengelige for . NETTO 4,5 og . NET for Windows 8。
Oversettelsesnotater
[1] Base Class Library, forkortet BCL. For mer informasjon om basisbiblioteket, vennligst delta i MSDN.
[2] Kamelkapsel, pukkelnomenklatur, også kjent som nedre kamelhylse. Formatet er at det første ordet begynner med en liten bokstav; Den første bokstaven i det andre ordet skrives med stor forbokstav, for eksempel: fornavn, etternavn.
[3] PascalMed innkapsling, Pascal-nomenklatur, også kjent som øvre kamel-forbokstav. Formatet er at den første bokstaven i hvert ord skrives med stor forbokstav, for eksempel: Fornavn, Etternavn, KamelSak. |