|
Dit artikel is gepubliceerd op zondag 31 juli 2011 op vbvoorbeelden, bezoek de website voor een recente versie van dit artikel of andere artikels.
Veronderstel volgende klasse Counter. Objecten van deze klasse hebben een Value en StepValue. Bij het verhogen ( Raise ) en verlagen ( Lower ) wordt de Value verhoogt of verlaagt met de StepValue.
Twee Counter objecten worden als logisch gelijk beschouwd indien ze dezelfde Value en StepValue toestand hebben, de Equals implementatie gaat dit hier dan ook na. Omdat Equals wordt geherdefinieerd, moeten we ook GetHasCode herdefiniëren en zorgen dat objecten die als logisch gelijk worden beschouwd dan ook dezelfde hash code opleveren. Dit garandeert dus ondermeer dat objecten van het type Counter als key voor een dictionary kunnen worden gebruikt. Visual Basic 2010 Broncode Namespace Example1 Class Counter Public Sub New( ByVal value As Integer) _Value = value End Sub Private _Value As Integer Public ReadOnly Property Value() As Integer Get Value = _Value End Get End Property Private _StepValue As Integer Public Property StepValue() As Integer Get StepValue = _StepValue End Get Set( ByVal value As Integer) _StepValue = value End Set End Property Public Sub Raise() _Value += StepValue End Sub Public Sub Lower() _Value -= StepValue End Sub Public Overrides Function Equals( ByVal obj As Object) As Boolean If obj IsNot Nothing AndAlso TypeOf obj Is Counter Then Dim other As Counter = DirectCast(obj, Counter) Equals = ( Me.Value = other.Value AndAlso _ Me.StepValue = other.StepValue) End If End Function Public Overrides Function GetHashCode() As Integer GetHashCode = Value Xor StepValue End Function End ClassEnd NamespaceDownload Visual Basic 2010 Broncode Download Visual C# Sourcecode
Gebruiken we Counter nu effectief als keytype voor een dictionary dan levert dit ons ook het verwachte en gewenste resultaat : Visual Basic 2010 Broncode Namespace Example1 Class Client Public Shared Sub Main() Dim counter1 As New Counter(1) With {.StepValue = 5} Dim counter2 As New Counter(1) With {.StepValue = 5} Dim counter3 As New Counter(1) With {.StepValue = 10} Dim hashtable1 As New Hashtable hashtable1.Add(counter1, "value") Console.WriteLine(hashtable1.Item(counter1).ToString()) Console.WriteLine(hashtable1.Item(counter2).ToString()) Console.WriteLine(hashtable1.Item(counter3) Is Nothing) Console.ReadLine() End Sub End ClassEnd NamespaceDownload Visual Basic 2010 Broncode Download Visual C# Sourcecode
Console Application Output value
value
True counter2, in tegenstelling tot counter3, heeft wel dezelfde Value en StepValue als counter1. Hierdoor worden counter1 en counter2 als logisch gelijk beschouwd, en zal de Hashtable bij het zoeken naar het element met key counter2 ook "value" opleveren.
Maken we van Counter een value type ( Structure ) dan hoeven we zelfs Equals en GetHashCode niet te overschrijven : Visual Basic 2010 Broncode Namespace Example2 Structure Counter Public Sub New( ByVal value As Integer) _Value = value End Sub Private _Value As Integer Public ReadOnly Property Value() As Integer Get Value = _Value End Get End Property Private _StepValue As Integer Public Property StepValue() As Integer Get StepValue = _StepValue End Get Set( ByVal value As Integer) _StepValue = value End Set End Property Public Sub Raise() _Value += StepValue End Sub Public Sub Lower() _Value -= StepValue End Sub End Structure Class Client Public Shared Sub Main() Dim counter1 As New Counter(1) With {.StepValue = 5} Dim counter2 As New Counter(1) With {.StepValue = 5} Dim counter3 As New Counter(1) With {.StepValue = 10} Dim hashtable1 As New Hashtable hashtable1.Add(counter1, "value") Console.WriteLine(hashtable1.Item(counter1).ToString()) Console.WriteLine(hashtable1.Item(counter2).ToString()) Console.WriteLine(hashtable1.Item(counter3) Is Nothing) Console.ReadLine() End Sub End ClassEnd NamespaceDownload Visual Basic 2010 Broncode Download Visual C# Sourcecode
Console Application Output value
value
True Logische gelijkheid wordt bij value types instanties by default gebaseerd op de volledige toestand van de instantie. Met volledige toestand wordt bedoeld de verzameling van alle veldwaardes. By default wordt ook de hash code voor value type instanties op alle velden gebaseerd.
Voor meer details over logisch gelijkheid bij value type en versus logische gelijkheid bij reference types zie het desbetreffende topic.
Het is echter niet aan te raden al te veel te vertrouwen op de overgeërfde implementatie van Equals en GetHashCode. Deze overgeërfde implementatie van GetHashCode bijvoorbeeld zal doorgaans wel een unieke hash code opleveren voor elk logisch uniek object, maar dit wordt in principe niet gegarandeerd. Ook wordt niet gegarandeerd dat verschillende versies van het .NET Framework dezelfde hash code opleveren voor objecten met dezelfde toestand. Dit kan bijvoorbeeld tot problemen leiden indien verschillende componenten/assemblies in een applicatie op verschillende versies van het Framework werken. Het is bijkomend ook zo dat de overgeërfde Equals implementatie, afhankelijk van de complexiteit van het type, een vrij grote performance overhead hebben. Het nagaan van gelijkheid tussen twee value type instanties met die overgeërfde implementatie kan dus vrij lang duren.
Conclusie is dat het in principe voor value types altijd aan te raden deze Equals en GetHashCode zelf te definiëren.
Hier in dit geval zouden we dat kunnen doen door volgende methods toe te voegen : Visual Basic 2010 Broncode Namespace Example2 Partial Structure Counter Public Overrides Function Equals( ByVal obj As Object) As Boolean If obj IsNot Nothing AndAlso TypeOf obj Is Counter Then Dim other As Counter = DirectCast(obj, Counter) Equals = ( Me.Value = other.Value AndAlso _ Me.StepValue = other.StepValue) End If End Function Public Overrides Function GetHashCode() As Integer GetHashCode = Value Xor StepValue End Function End StructureEnd NamespaceDownload Visual Basic 2010 Broncode Download Visual C# Sourcecode
Indien we logische gelijkheid tussen twee Counters enkel willen baseren op Value en niet meer op Value en StepValue, krijgen we niet meer het gewenste resultaat.
In dat geval moeten we sowieso wel Equals en GetHashCode overschrijven : Visual Basic 2010 Broncode Namespace Example3 Structure Counter Public Sub New( ByVal value As Integer) _Value = value End Sub Private _Value As Integer Public ReadOnly Property Value() As Integer Get Value = _Value End Get End Property Private _StepValue As Integer Public Property StepValue() As Integer Get StepValue = _StepValue End Get Set( ByVal value As Integer) _StepValue = value End Set End Property Public Sub Raise() _Value += StepValue End Sub Public Sub Lower() _Value -= StepValue End Sub Public Overrides Function Equals( ByVal obj As Object) As Boolean If obj IsNot Nothing AndAlso TypeOf obj Is Counter Then Dim other As Counter = DirectCast(obj, Counter) Equals = ( Me.Value = other.Value) End If End Function Public Overrides Function GetHashCode() As Integer GetHashCode = Value End Function End Structure Class Client Public Shared Sub Main() Dim counter1 As New Counter(1) With {.StepValue = 5} Dim counter2 As New Counter(1) With {.StepValue = 5} Dim counter3 As New Counter(1) With {.StepValue = 10} Dim hashtable1 As New Hashtable hashtable1.Add(counter1, "value") Console.WriteLine(hashtable1.Item(counter1).ToString()) Console.WriteLine(hashtable1.Item(counter2).ToString()) Console.WriteLine(hashtable1.Item(counter3).ToString()) Console.ReadLine() End Sub End ClassEnd NamespaceDownload Visual Basic 2010 Broncode Download Visual C# Sourcecode
Console Application Output value
value
value
Dit artikel is gepubliceerd op zondag 31 juli 2011 op vbvoorbeelden, bezoek de website voor een recente versie van dit artikel of andere artikels.
|