hashtable add fails unexpectedly when using attribute instances as keys

B

Bob

If two attribute instances of the same type have all their fields values
identical, the compiler will say that they are not equal to each other, yet
adding them both as keys in a hashtable will throw an exception. Is this
expected behavior or a bug?

I've included an example below. Run the code as is and no exception is
thrown. Run it with both attributes contructed identically, or remove all
fields in the TestAttribute class, and an exception is thrown.

Bob

------------------------

Imports System.ComponentModel
Imports System.Reflection

Module Main

Public Sub main()
Try
Dim ht As New Hashtable
For Each t As Type In [Assembly].GetExecutingAssembly.GetTypes
For Each atr As Attribute In
t.GetCustomAttributes(GetType(TestAttribute), False)
ht.Add(atr, "some value")
Next
Next
MsgBox("no error")
Catch ex As Exception
MsgBox(ex.ToString)
End Try
End Sub

End Module

<AttributeUsage(AttributeTargets.Class)> _
Public Class TestAttribute
Inherits Attribute
Public Sub New(ByVal ifoo As String)
Foo = ifoo
End Sub
Public ReadOnly Foo As String
End Class

<TestAttribute("test1")> _
Public Class test1
End Class

<TestAttribute("test2")> _
Public Class test2
End Class
 
M

Mattias Sjögren

If two attribute instances of the same type have all their fields values
identical, the compiler will say that they are not equal to each other,

When will the compiler say that?

yet adding them both as keys in a hashtable will throw an exception. Is this
expected behavior or a bug?

Well if you call Object.Equals() on one of the attribute objects and
pass in the other, it returns True. And they return the same value
from GetHashcode(). So it looks like expected behavior to me.



Mattias
 
B

Bob

Still learning. I guess (duh) I should have checked the hashcodes. But I
never knew you can have one object1 is object2 = False and yet have Equals
say true and the hashcodes be equal.
When will the compiler say that?

See below for an illustration.

Bob

------------

Imports System.Reflection

Module Main

Public Sub main()
Try
Dim a1 As New TestAttribute("foo")
Dim a2 As New TestAttribute("foo")
MsgBox("a1 is a2 is " & (a1 Is a2))
MsgBox("a1 equals a2 is " & a1.Equals(a2))
MsgBox("a1.GetHashCode = a2.GetHashCode is " & (a1.GetHashCode =
a2.GetHashCode))
Dim ht As New Hashtable
ht.Add(a1, a1.foo)
ht.Add(a2, a2.Foo)
MsgBox("no error adding items to hashtable")
Catch ex As Exception
MsgBox(ex.ToString, , "error adding items to hashtable")
End Try
End Sub

End Module

Public Class TestAttribute
Inherits Attribute
Public Sub New(ByVal ifoo As String)
Foo = ifoo
End Sub
Public ReadOnly Foo As String
End Class
 
B

Bob

Here is what is unexpected - change TestAttribute so that it's not
inheriting from Attribute and magically the two class instances get two
different hashcodes instead of the same! I just want to know why this
happens and if there is any way I can predict which classes will act like
this.

Bob
 
M

Mattias Sjögren

Bob,
I just want to know why this
happens and if there is any way I can predict which classes will act like
this.

A class can override the GetHashcode method and return whatever value
it wants. If a class doesn't override GetHashcode, the default
implementation in System.Object returns the value of a sequential
counter, so each object gets it's own semi-unique value.
System.Attribute apparently overrides GetHascode and returns a value
derived from the attribute constructor and/or initialization data.



Mattias
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Top