On this page.... RSS 2.0 | Atom 1.0 | CDF
# Wednesday, March 30, 2005

I just had a strange bug pop up in this framework I've built.  It uses a number of custom attributes.  I have a base attribute and a corresponding collection.  On my collection, there's an Add method that checks to ensure the attribute hasn't already been added before adding, since ArrayList's default implementation is to allow duplicates and nulls.

I declared a type and applied a few of these attributes to different properties on the type, and yet, when I went to add them to my collection, I found that it was only adding the first attribute of a particular attribute type. 

So I looked up the docs on ArrayList.Contains to find out it uses Object.Equals in order to determine if the object is in the list.  So, on a hunch, I looked up System.Attribute, and sure enough, they override Object.Equals.  Here's a link to the help on that.  As you can see, it isn't very helpful.  It doesn't describe how it is changing the semantics of Object.Equals in any way.

So then it was time to pull out my trusty friend Reflector.  Looking at what Attribute.Equals is doing wasn't particularly helpful either because it keeps making external calls, but from what I can gather, it attempts to compare the values of all the fields on the two instances in question.  So you'd think, hey, this is a fair way to determine equality, right?

Wrong.  It doesn't work.  The two attributes I was having problems with had several differing values in their fields, yet this Equals method did not catch that.  Needless to say, this is obviously a bug.  I'd love to hear, in any case, the reasoning why Attribute overrides Equals and, in addition, why the help docs don't explain it one bit.

In the meantime, life goes on, and I had to figure out a separate implementation of Equals that'd work for my needs.  Unfortunately, as far as I can tell, there's no way to call the default Object.Equals method because, as you can see in Reflector, it will simply use objA == objB, which will only redirect you to the most overridden implementation. 

So since I couldn't compare references themselves, which is what I would prefer, I decided to just use two of my properties that were sufficient to meaningfully give the attributes separate identities. 

"Sure," you might say, "you should always do this."  But most of the time I don't see the point; it is often more confusing to do so because, apart from System.String, developers expect reference types to compare equality based on references not values, especially when dealing with custom domain types. 

So I'd say it's generally a bad idea to override Equals unless you really need to because, once you do that, you should also override GetHashCode and, at that point, you may as well just toss the computer out the window and give all your money to charity.  It's just a lot of (usually) unnecessary work that can actually cause confusion and introduce unexpected bugs into your apps.

Anyways, to bring this to a close, if anyone can explain the rationale behind what Attribute is doing, I'd appreciate it.  And if any MS BCL or corlib guys read this, please update the docs on Attribute.Equals to be more meaningful.

Wednesday, March 30, 2005 3:35:39 PM (Eastern Standard Time, UTC-05:00)  #    Disclaimer  |  Comments [0]  |  Tracked by:
"generic diet pills" (generic diet pills) [Trackback]
"online poker player" (online poker player) [Trackback]

Comments are closed.

The opinions expressed herein are solely my own personal opinions, founded or unfounded, rational or not, and you can quote me on that.

Thanks to the good folks at dasBlog!

Copyright © 2019 J. Ambrose Little