© 2011, Flemming Koch Jensen
Alle rettigheder forbeholdt |
Collection klasser |
Ligesom C++ har sit Standard Template Library (STL) og Java har sine collection klasser i java.util, sådan har også C# en samling collection klasser. Det er dem vi vil se nærmere på i det følgende. De befinder sig alle i det namespace der hedder: System.Collections. Man skal derfor huske: | ||
| ||
i starten af de kildetekster, der anvender collection klasser. | ||
1. Interfaces | ||
Containerne, vi senere skal se på, implementere diverse interfaces. Vi vil derfor først se disse interfaces og hvad der er formålet med dem. | ||
Der er i alt otte interfaces; hvoraf de seks har relationer til hinanden. Vi vil først se på de følgende fire: | ||
Figur 1: IEnumerable's interfaces |
| |
1.1 IEnumerable | ||
Øverst i figur 1's hierarki finder vi IEnumerable. Interfacet har kun en metode: | ||
| ||
Som vi senere skal se i beskrivelsen af IEnumerator, kan en IEnumerator bruges til at iterere en collection. IEnumerable interfacet giver os blot adgang til en fabriks-metode, der giver os en sådan iterator. Dette er i tråd med idéen i Iterator Pattern. | ||
Dette interface er særlig vigtigt af en speciel grund. Instanser af klasser, der implementerer IEnumerable, kan nemlig gennemløbes med den specielle variant af for-løkken: foreach: | ||
1.1.1 foreach-løkken | ||
foreach-løkken har følgende syntax: | ||
| ||
Det skal læses som: "For hver <variabel> af typen <Element-klasse> i <Container> så:". I foreach-løkkens krop bruger man <variabel> som reference til den aktuelle instans af <Element-klasse>, som man er kommet til i iterationen. | ||
Lad os først se et eksempel med, hvad der ellers er en primitiv type, int: | ||
| ||
Arrays | Der indgår ikke nogen egentlige klasser i dette eksempel - det vil vi vende tilbage til når vi ser på nogle containerklasser - men den generelle mulighed for at anvende foreach-løkken med arrays illustrerer idéen. | |
Lad os dernæst se et eksempel hvor <Element-klasse> i det mindste er en rigtig klasse: | ||
| ||
Vi arbejder stadig med et array som <Container>, men <Element-klasse> er nu klassen string. | ||
Som nævnt vil vi vende tilbage til foreach-løkken, efterhånden som vi lærer nogle collection-klasser som vi kan bruge den på. | ||
1.2 ICollection | ||
ICollection implementerer IEnumerable, og alle containere implementerer ICollection. Det er derfor et vigtigt interface, da det fortæller os om C#'s opfattelse af en container. | ||
1.2.1 Properties | ||
ICollection har følgende properties (alle er kun get-properties): | ||
| ||
Count fortæller hvor mange elementer der er i containeren (kardinaliteten). IsReadOnly, om man kun kan læse fra den. IsSynchronized fortæller om containeren er thread-safe, og SyncRoot returnerer et objekt, som man kan synkronisere på. | ||
[Note: Det er uklart om IsReadOnly er erklæret i ICollection eller først optræder i IList og IDirectory] | ||
1.2.2 Metoder | ||
ICollection har kun én metode: | ||
| ||
Kopierer til array | Array er baseklasse for alle arrays. Den første parameter kan derfor være et hvilket som helst array (det skal dog være en-dimensionelt). Metoden kopierer elementerne fra containeren til det array som gives med som parameter. Denne kopiering starter fra det angivne index i array. Der kastes en ArgumentException hvis der ikke er plads. | |
1.3 IList | ||
Har index'er | IList repræsenterer en container hvor elementerne kan refereres med index. Det er derfor ikke overraskende at IList har en index'er. | |
1.3.1 Properties | ||
IList har følgende property (er kun en get-property): | ||
| ||
IsFixedSize fortæller om containeren har en fast kapacitet - dvs. om der er et fast maximum for, hvor mange elementer den kan indeholde. | ||
1.3.2 Metoder | ||
Først er der metoder til at tilføje elementer | ||
Tilføje |
| |
Add returnerer hvor elementet er blevet placeret (index). Insert placerer elementet det angivne sted. Insert kan kaste en ArgumentOutOfRangeException. | ||
Dernæst er der de søgende metoder: | ||
Søge |
| |
Contains fortælle om elementet overhovedet findes i containeren, mens IndexOf fortæller hvor (index). Hvis elementet ikke findes, returnerer IndexOf: -1. | ||
Hvis man skulle få behov for at fjerne elementer, er der: | ||
Fjerne |
| |
Remove fjerner et element. Bemærk at denne metode ikke fortæller om et element rent faktisk er blevet fjernet; hvis det er vigtigt at vide, må man først kalde Contains. RemoveAt fjerner elementet på den angivne placerering (index). RemoveAt kan kaste en ArgumentOutOfRangeException. | ||
Endelig er der: | ||
| ||
som tømmer containeren for alle elementer - så den er tom. | ||
1.4 IDictionary | ||
Mapping | Et IDictionary repræsenterer en samling af elementer med tilhørende nøgle. Man kalder det også en mapping mellem nøgler og værdier - en entydig afbildning af nøgler over i værdier - en funktion (i matematisk forstand). I Java anvendes betegnelsen "map" for disse containere. | |
Har index'er | IDirectory har en index'er. Den tager nøglen som index og giver elementet. | |
1.4.1 Properties | ||
IList har følgende properties (alle er kun get-properties): | ||
| ||
Ligesom for IList fortæller IsFixedSize om containeren har en fast kapacitet. | ||
Keys og Values returnerer containerens nøgler henholdsvis elementer i en container (hvor om det kun vides, at den implementerer ICollection interfacet). | ||
1.4.2 Metoder | ||
| ||
Add tilføjer et element. Bemærk at key ikke må være null. Add kaster en ArgumentAxception, hvis key allerede findes i containeren. | ||
Contains returnerer om en bestemt nøgle findes i containeren. | ||
Remove fjerner et element fra containeren. Denne metode oplyser ikke om elementet fandtes før det blev fjernet. | ||
Clear tømmer containeren for elementer. | ||
Endelig har IDictionary en anden udgave af GetEnumerator (ellers erklæret i IEnumerable): | ||
| ||
Denne metode returnerer en særlig iterator til directories - mere om den senere. | ||
| ||
De to sidste, af de seks interfaces der har relationer til hinanden, udgør naturligvis et langt mindre hierarki: | ||
Figur 2: IEnumerator's interfaces |
| |
Ikke robuste | Der er i begge tilfælde tale om iteratorer. Man skal bemærke, at der ikke er tale om robuste iteratorer. | |
1.5 IEnumerator | ||
IEnumerator repræsenterer en generel iterator, som returneres af fabriks-metoden i IEnumerable. | ||
Iteratorerne initialiseres til at være én position før det første element i containeren, så man skal altid gå et skridt frem for at finde det første element. | ||
1.5.1 Properties | ||
IEnumerator har følgende property (er kun get-property): | ||
| ||
Current returnerer det element som iteratoren er kommet til. | ||
1.5.2 Metoder | ||
| ||
MoveNext flytter frem til det næste element, og returnerer boolsk om der er et sådant element. Hvis man når hen til enden af containeren, vil gentagne kald af MoveNext blive ved med at returnere false. | ||
Reset placerer iteratoren én position før det første element i containeren. | ||
Bemærk at man altid skal kalde MoveNext efter Reset (eller når man første gang anvender iteratoren) for at finde det første element. At iteratoren starter én position før første element i containeren, gør det (som bekendt) enkelt at opbygge en iteration over containerens elementer med en while-løkke: | ||
| ||
1.6 IDictionaryEnumerator | ||
IDictionaryEnumerator anvender de samme iterator-metoder som den arver fra IEnumerator. Det nye i IDictionaryEnumerator er behovet for at erstatte Current, med properties der tilgår nøglen og det tilhørende element. | ||
1.6.1 Properties | ||
IDictionaryEnumerator har følgende properties (alle er kun get-properties): | ||
| ||
Key og Value giver adgang til "Current" elementet (der her er et 2-tuple bestående af nøgle og tilhørende element). Entry giver adgang til dem begge på en gang, samlet i en instans af DictionaryEntry, der er en struct med de to properties Key og Value. | ||
| ||
Endelig har vi to interfaces, der ikke har relationer til de andre: | ||
1.7 IComparer | ||
IComparer kunne lige så godt være et delegat, da det er et interface med kun én metode og ingen properties. Idéen med IComparer er at stille en metode til rådighed, som kan sammenligne to objekter. Metoden er: | ||
| ||
Metoden fungerer på samme måde som compareTo-metoden i Java. | ||
1.8 IHashCodeProvider | ||
IHashCodeProvider kunne for så vidt også være et delegat, da den ligeledes kun har én metode og ingen properties. Metoden er: | ||
| ||
Metoden er en hashfunktion, der returnerer en hashværdi for det givne objekt. | ||
2. Containere | ||
De interfaces vi har gennemgået i det foregående implementeres i forskelligt omfang af de følgende container klasser. Alle container-klasser implementerer ICollection og IEnumerable. Metoder og properties fra disse to interfaces vil derfor ikke blive nævnt i det følgende: | ||
2.1 ArrayList | ||
IList | ArrayList er et dynamisk array af object's. Det fungerer i stil med java.util.Vector i Java (Ligesom Vector fordobler sin størrelse, når den løber fuld, således gør ArrayList det også). ArrayList implementerer IList. Der ud over har ArrayList en række properties og metoder: | |
2.1.1 Konstruktorer | ||
ArrayList har følgende konstruktorer: | ||
| ||
Initiel kapacitet | Default-konstruktoren initialiserer naturligvis listen til at være tom og have den initielle default kapacitet (16). Konstruktoren der tager en int som parameter sætter i stedet den initielle kapacitet til den angivne størrelse. | |
Kopierer | Den sidste konstruktor kopierer elementerne fra den givne container, til sig selv, og sætter sin kapacitet til det kopierede antal elementer - dvs. ingen overskydende plads! | |
2.1.2 Properties | ||
ArrayList har følgende property (er kun get-property): | ||
| ||
Capacity fortæller hvor meget plads (totalt) der er i arrayet, på nuværende tidspunkt. Eftersom ArrayList er et dynamisk array, vil det udvide sin kapacitet efter behov. | ||
2.1.3 Metoder | ||
ArrayList er rig på metoder - der er over tredive. Vi vil derfor nøjes med dem, der må formodes at være de mest anvendte: | ||
| ||
| ||
| ||
| ||
| ||
| ||
| ||
| ||
| ||
2.2 BitArray | ||
Boolske værdier som pakkede bits | Navnet BitArray beskriver primært den interne repræsentation der anvendes, nemlig pakkede bits. Med pakkede bits menes bits der er samlet i de enkelte bytes (8 stk.) så der ikke går plads til spilde. Ud ad til fremstår BitArray som en container, der kan indeholde boolske værdier - dvs. elementer af typen bool. | |
2.2.1 Konstruktorer | ||
BitArray har først og fremmest en copy-konstruktor: | ||
| ||
Ud over copy-konstruktoren er der også, hvad man kunne kalde en "virtuel set-konstrutor". Ud ad til fremstår BitArray jo som et array af boolske værdier. | ||
Dernæst har vi et par konstruktorer, der laver initialiserede BitArray's af en vis længde: | ||
| ||
I begge tilfælde angiver length længden af BitArray'et. I det første tilfælde initialiseres alle indgange til false (0), mens den anden giver mulighed for at man selv kan angive initialiseringsværdien. | ||
Endelig har BitArray et par konstruktorer, der gør det muligt at initialisere ud fra den interne repræsentation - nemlig pakkede bits: | ||
| ||
Den første går direkte på den interne repræsentation - et array af byte's, mens den anden tager lidt større bider (en int er som bekendt fire bytes). | ||
Lad os se et eksempel (forudsætter at man er fortrolig med hexadecimal notation): | ||
| ||
| ||
Den første bit er bit 0, den næste er bit 1 osv. Det kan være lidt svært at gennemskue output'et, da det skal læses bagfra; hvis man vil sammenligne med de to arrays. Omsætter man i første omgang hver nibble til hex, får man: | ||
| ||
Dette skal fortsat læses bagfra. I den øverste linie er 1 den første nibble - dvs. mindst betydende - den der repræsenterer indgangene 0-3 i bArray. Læser man bagfra, får man: | ||
| ||
Hvis vi tager den nederste linie først, ser vi at bit 0-15 i vores integer er blevet afbildet direkte over i indgang 0-15 i arrayet. For byte-arrayet er det det samme system, men måske lidt sværere at se. Den første byte i vores array: bytes[0] er blevet indgang 0-7, det næste bytes[1] er blevet indgang 8-15 osv. På samme måde som for int'en svarer bit-positionerne i den binære repræsentation til indgangene (absolut for bytes[0] og relativt for de andre). | ||
2.2.2 Properties | ||
BitArray har propertien (kun get-property): | ||
| ||
der giver arrayets længde - dvs. antallet af bits i arrayet. | ||
BitArray har desuden en index'er | ||
2.2.3 Metoder | ||
| ||
| ||
| ||
2.3 Hashtable | ||
2.4 Queue | ||
2.5 SortedList | ||
2.6 Stack | ||
3. Type-specifikke containere | ||
3.x StringCollection | ||