Generic collections i .NET 2.0

Ved .NET 2.0 introducerede Microsoft generics, som er kendt som templates fra C++. Ved lejligheden fik collections klasserne et nytårskur. Der findes en række nye collections i 2.0 frameworket. Jeg vil prøve at give beslutningshjælp til hvilken collection man bedst anvender og giver nogle korte implementeringseksempler på sortering, søgning og ‘custom’ hashnøgler.

Navngivning af generic collections er lidt uheldig i den forstand, at den ikke 100 % matcher den i litteraturen anvendte. Se tabellen nedenfor for en oversigt af udvalgte collections. Tiderne for de enkelte operaterion er hentet fra "MSDN Library for Visual Studio 2005".

  Sorted
Dictionary
Dictionary List LinkedList
Item O(log n) O(1) O(1) O(n)
BinaryFind na na sort (O(n2)) + O(log n) na
Find O(n) O(n) O(n) O(n)
Add O(n2) O(n) O(n) O(1)
Remove O(log n) O(1) O(n) O(1)
Interfaces

ICollection
IEnumerable
IDictonary

ICollection
IEnumerable
IDictonary

ICollection
IEnumerable
IList

ICollection
IEnumerable

Dictionary collection er den nye hashtabel og har få members. List collection derimod byder på nyttige funktioner så som sortering, søgning og binær søgning. Det sidst nævnte forudsætter at listen er sorteret.

Interfaces

Tabellen nævner alle interfaces, som de viste collections implementerer. Dette kan med fordel anvendes til at gøre det nemmere at ændre den valgte collection senere i implementering. Det begrænser dog mulighederne tydeligt, fordi alle collections kun har ICollection og IEnumerable til fælles:

ICollection: Count, IsSynchronized, SyncRoot, CopyTo().

IEnumerable: GetEnumerator().

Derfor kan det være en god idé at valge den rigtige collection fra begyndelsen. Alternativ kan du nedarve fra collection klassen og definere dit eget interface, så skal der kun rettes i en klasse, når du fortryder dit valg.

Sortering med List<>

Sort() metoden kan nemt anvendes med en in-line delegate eller en metode. Her vises en in-line delegate som sorterer listen efter fag id ascending. Delegate’n benytter decimals CompareTo() metode for at sammenligne to fag id’er, som er af typen decimal.

List<Underfag> underfagList = new List<Underfag>();
underfagList.Sort(
   delegate(Underfag x, Underfag y)
   { return x.FagId.CompareTo(y.FagId); }
);

Find med List<>

Find() returner det første fundne element og FindAll() returner alle fundne elementer som en List<>. Metoderne kan igen nemt anvendes med en in-lined delegate, en metode eller et objekt med en metode for at overgive parametre. Her vises en in-line delegate, som anvendes i en unittest for at tjekke om prøveholdet 14669 er allokeret. Det er ikke en god idé at gøre det så kompakt, hvis du ikke er 100 % sikker på at listen indeholder prøveholdet. Ellers får du ein NullReferenceException, fordi Find() returnerer null hvis elementet ikke findes i listen.

Assert.IsTrue(

   allokeringData.PrøveholdList.Find(

   delegate(Prøvehold p)
   { return p.PpPrøveholdId == 14669; }).IsAllokeret,

   "Prøvehold 14669 er ikke markert som allokeret."
);

Tilpasset hashnøgle med Dictionary<>

Det kan være en hastigheds fordel at danne en hashnøgle udfra egne kriterier. Hvis opslaget skal være baseret på mere end én indeks, er du nødt til at definere din egen hashnøgle. Du kan enten lave en hashnøgle klasse, som overrider GetHashCode() og Equals() metoder fra Object klassen, eller anvende en sammenkædede string nøgle.

Her vises et eksempel på hashnøgle klassen InhabilitetCensurKey, som anvendes som nøgle i en Dictionary med InhabilitetCensur elementer.

Nøgle klassen:

public class InhabilitetCensurKey {

private const string HASH_TEMPLATE = "{0};{1}";

 

/// <summary>

/// Anvendes til at sammenligne to objekter af denne type.

/// </summary>

/// <param name="obj"></param>

/// <returns></returns>

public override bool Equals(object obj) {

   return (this.InstitutionId == (obj as   
   InhabilitetCensurKey
).InstitutionId &&

   this.KandidatId == (obj as  
   InhabilitetCensurKey
).KandidatId);

}

/// <summary>

/// Returnerer hashkoden til anvendelse i hashtabel/ dictonary.

/// </summary>

/// <returns></returns>

public override int GetHashCode() {

   return String.Format(HASH_TEMPLATE,
   this.InstitutionId, this.KandidatId).GetHashCode();

}

}

Anvendelse af Dictionary’en:

Det må desværre vente, fordi LiveWriter ikke tillader flere tegn i HTML view!

Leave a Reply

Your email address will not be published. Required fields are marked *