|
Dit artikel is gepubliceerd op zondag 31 juli 2011 op vbvoorbeelden, bezoek de website voor een recente versie van dit artikel of andere artikels.
22.8.1. Eigen IList ImplementatiesEen eigen implementatie van de IList interface kan eenvoudig worden opgesteld door bijvoorbeeld intern gebruik te maken van een ArrayList. ArrayList implementeert reeds IList en beschikt dan ook reeds over implementaties van de in IList gedefinieerde members. Door in onze implementatie van deze members te delegeren naar de gelijknamige van ArrayList vereenvoudigen we in sterke mate het werk om deze members van een implementatie te voorzien : Visual Basic 2010 Broncode Option Strict OnImports System.Collections Public Class Person Private _Name As String Public Property Name() As String Get Name = _Name End Get Set( ByVal value As String) _Name = value End Set End PropertyEnd ClassDownload Visual Basic 2010 Broncode Download Visual C# Sourcecode
Namespace OwnIListImplementation Public Class Persons : Implements IList Private _Items As IList = New ArrayList Public Function GetEnumerator() As IEnumerator _ Implements IList.GetEnumerator GetEnumerator = _Items.GetEnumerator End Function Public Sub CopyTo(ByVal array As System.Array, ByVal index As Integer) _ Implements IList.CopyTo _Items.CopyTo(array, index) End Sub Public ReadOnly Property Count() As Integer Implements IList.Count Get Count = _Items.Count End Get End Property Public Function Add(ByVal value As Object) As Integer _ Implements IList.Add Add = _Items.Add(value) End Function Default Public Overridable Property Item(ByVal index As Integer) _ As Object Implements IList.Item Get Item = _Items.Item(index) End Get Set(ByVal value As Object) _Items.Item(index) = value End Set End Property End Class End Namespace Bovenstaande Persons is niet meer dan een simpele "wrapper" ( "verpakking" ) rond een ArrayList. We hebben hier niet veel aan, we kunnen in clients evengoed een ArrayList object gebruiken in plaats van een Persons object. Persons biedt niets meer dan ArrayList.
Sterker nog het heeft dezelfde nadelen als ArrayList. Er wordt gewerkt met elementen van type Object. De Add method verwacht een value As Object en de Item bijvoorbeeld levert een Object op.
Als het de bedoeling zou zijn deze collectie enkel voor Person items te gebruiken, dan wordt bijvoorbeeld niet at compiletime verhinderd dat men items van een ander type probeert toe te voegen (1). Bij het raadplegen van een element via de Item property moeten we dan nog eens casten om aan de specifieke members van Person te kunnen (2). Item leverde immers het element in Object vorm op. Namespace OwnIListImplementation Public Class Client Public Shared Sub Main() Dim persons1 As New Persons persons1.Add("dummy") Console.Write(DirectCast(persons1.Item(0), Person).Name) Console.ReadLine() End Sub End Class End Namespace boven
22.8.2. Strongly Typed IList ImplementatieDeze nadelen kunnen we wegwerken door de publieke interface van onze wrapper aan te passen. Door in de publieke Add method bijvoorbeeld enkel Person parameterwaardes toe te laten, maken we de list collectie - op zijn minst op het vlak van elementen toevoegen - "strongly typed" : Namespace OwnStronglyTypedIListImplementation Public Class Persons : Implements IList Public Function Add(ByVal value As Person) As Integer End Function Private Function Add(ByVal value As Object) As Integer _ Implements IList.Add If TypeOf value Is Person Then Add = Add(DirectCast(value, Person)) End If End Function Default Public Property Item(ByVal index As Integer) As Person Get Item = DirectCast(getItem(index), Person) End Get Set(ByVal value As Person) End Set End Property Private Property getItem(ByVal index As Integer) As Object _ Implements IList.Item Get End Get Set(ByVal value As Object) End Set End Property End Class End Namespace Nu wordt reeds at compiletime verhinderd dat wat iets anders dan een Person aan de collectie toevoegen (1) : Namespace OwnStronglyTypedIListImplementation Public Class Client Public Shared Sub Main() Dim persons1 As New Persons Console.Write(persons1.Item(0)) Dim arrayList1 As New ArrayList arrayList1.Add("dummy") Console.Write(DirectCast(arrayList1.Item(0), Person).Name) Console.ReadLine() End Sub End Class End Namespace Ook het casten van een call naar Item is niet meer noodzakelijk (2), deze levert nu immers een element reeds in Person vorm op.
Ons eigen collectietype heeft nu wel voordelen op ArrayList, die zelf nog altijd in zijn publieke interface gebruik maakt van het itemtype Object. Geen compiletime controle op itemtype (3) en meer castingoperaties (4) zijn daarvan het noodzakelijke gevolg.
Bemerk dat we nog altijd, naast de typesafe Add method, ook een implementatie voor IList.Add(value As Object) moeten voorzien. Maar door deze implementatie in te kapselen ( Private ) vermijden we op zijn minst deze non typesafe method in de publieke interface.
Ook members als IndexOf, Insert, Remove en Contains zouden met parameters van type Person moeten werken, om deze collectie volledig strongly typed te maken. boven
22.8.3. De System.Collections.CollectionBase KlasseNog altijd is het vrij veel werk om in een eigen collectie de IList interface te implementeren. Daar komt nog eens bij dat je voor elk verschillend itemtype waarvoor je een strongly typed list collectie wil dit werkt moet herhalen. Herhalen terwijl vele members, met uitzondering van de members die noodzakelijk zijn om de collectie strongly typed te maken, waarschijnlijk op dezelfde manier geïmplementeerd worden.
Om dit werk te verlichten is reeds de System.Collections.CollectionBase klasse voorzien. Deze is speciaal gemaakt om strongly typed list collecties op te baseren. CollectionBase maakt reeds intern gebruik van een ArrayList object om de elementen in te beheren en bevat reeds de implementaties zoals Clear en RemoveAt bijvoorbeeld die voor strongly typed collecties van eender welk itemtype toch waarschijnlijk identiek zouden zijn.
Het enigste wat je nog moet naast het overerven van de members van CollectionBase, is het voorzien van typesafe members als Item, Add, IndexOf, Insert, Remove en Contains, of een subset ervan indien ze niet allemaal gewenst zijn. Dergelijke members moeten we toevoegen omdat deze in hun signatuur gebruik moeten maken van parameters en returntypes van het specifieke itemtype waarvoor de strongly typed list collectie wordt gemaakt.
De interne ArrayList is in je eigen toe te voegen member implementaties ondermeer te benaderbaar via de ingekapselde Protected ReadOnly Property List() As IList : Visual Basic 2010 Broncode Namespace CollectionBaseIListImplementation Public Class Persons : Inherits CollectionBase Default Public Property Item( ByVal index As Integer) As Person Get Item = DirectCast(List.Item(index), Person) End Get Set( ByVal value As Person) List(index) = value End Set End Property Public Function Add( ByVal value As Person) As Integer Return List.Add(value) End Function Public Function IndexOf( ByVal value As Person) As Integer Return List.IndexOf(value) End Function Public Sub Insert( ByVal index As Integer, ByVal value As Person) List.Insert(index, value) End Sub Public Sub Remove( ByVal value As Person) List.Remove(value) End Sub Public Function Contains( ByVal value As Person) As Boolean Return List.Contains(value) End Function End ClassEnd NamespaceDownload Visual Basic 2010 Broncode Download Visual C# Sourcecode
At compiletime wordt nu opnieuw nagegaan of we wel een item van type Person toevoegen (1). Ook het casten van een call naar Item is niet meer noodzakelijk om de voor Person specifieke members te benaderen (2). Visual Basic 2010 Broncode Namespace CollectionBaseIListImplementation Public Class Client Public Shared Sub Main() Dim persons1 As New Persons Console.Write(persons1.Item(0)) Console.ReadLine() End Sub End ClassEnd NamespaceDownload Visual Basic 2010 Broncode Download Visual C# Sourcecode
Dit artikel is gepubliceerd op zondag 31 juli 2011 op vbvoorbeelden, bezoek de website voor een recente versie van dit artikel of andere artikels.
|