OBSOLETE CONTENT
The author of
this post has determined that this content is obsolete. Use at your own
risk! Blog posts are a point-in-time snapshot of the blogger's thinking
and should not be assumed to represent this blogger's current opinions.
This post was left up for historical purposes.
Last week I posted about starting a new project here at the port. I'm entering new development territory with this, specifically, I'm 1) Doing test-driven developmet with NUnit, 2) Using Custom Entities instead of DataSets and 3) Developing my buisness tier components as WSE services. I've been having fun. I'm very into the test-driven developent thing, NUnit Rocks! I'm definitely writing much more solid code. I'm going to post about that later, but I wanted to share some thoughts on using Custom Entities vs. DataSets here.
I'm adding a whole new layer to my Common tier, consisting of my new custom entities. These are hopefully going to be the building blocks of our framework someday, and consist of our basic business entities.
DataBinding: This was one thing I was slightly worried about with Custom Entities, but it's works great. I've created strongly-typed collection classes for each entity, and I can databind these no problem. Being used to the ease of binding with DataSets, this was a relief. The one thing I do miss is having the UI component to assist with the DataBinding which you get with DataSets, but that's not a big deal.
Equality: This was somewhat of an eye opener for me. As I was putting my entites into collections, I noticed that they were going in multiple times, because the hash codes for object that I consider equal were different. Also, I noticed that if I created two entity objects with exactly the same data a test for equality would fail. To fix this, I found I needed to override Equals(), ==, != and GetHashCode().
Now, there are some suggestionsfrom MS (Guidelines for Implementing Equals and the Equality Operator (==)) that give some guidelines for doing this, and Overview of the Object Class had some good pointers too, but I discovered (via my trusty NUnit) that it's a little more complicated than it seems. First, a warning: The suggestions in this article are not correct. In fact, even the comments that attempt to correct the arcticle are incorrect! And, definitely don't do this!
So after some testing, here's a few guidelines for overriding Equals(), ==, != and GetHashCode():
If you're testing for NULL using = = comparisons within your overrides for = =, make sure you use the base class' (object) operator. This may seem obvious, but you'll get stack overflows really quickly without code like this.
public static bool operator ==(USCity x, USCity y)
{
if ((object) x == null) return ((object) y == null);
return x.Equals(y);
}
When overriding GetHashCode() make sure you test your reference types, like String, for NULL before bitwise - or'ing the hash codes. For example, code like this will break if stateCode or city are NULL:
public override int GetHashCode()
{
return this.stateCode.GetHashCode() ^ this.city.GetHashCode();
}
This may seem obvious as well, but it took me some Unit testing to realize this. So, once I got everything straight, my simple class ended up looking like this:
public class USCity
{
private string city;
private string stateCode;
.. Public Properties Removed for Brevity ..
public static bool operator ==(USCity x, USCity y)
{
if ((object) x == null) return ((object) y == null);
return x.Equals(y);
}
public static bool operator !=(USCity x, USCity y)
{
return !(x == y);
}
public override bool Equals(object obj)
{
if(obj is USCity)
if(((USCity)obj).stateCode == this.stateCode &&
((USCity)obj).city == this.city)
return true;
return false;
}
public override int GetHashCode()
{
int hashCode = 0;
if(this.stateCode != null) hashCode ^= this.stateCode.GetHashCode();
if(this.city != null) hashCode ^= this.city.GetHashCode();
return hashCode;
}
}
And here's my UnitTest that I used to sort this out this equality stuff:
[Test]
public void TestCityEquality()
{
USCity city = null;
USCity city2 = null;
Assert.AreEqual(city, city2, "Nulls Should be Equal");
city = new USCity();
city.City = "Norfolk";
city.StateCode = "VA";
Assert.IsTrue(city != city2, "Should not be Equal");
city2 = new USCity();
city2.City = "Norfolk";
city2.StateCode = "VA";
Assert.IsTrue(city == city2, "Should be Equal");
city2.City = "Portsmouth";
Assert.IsTrue(city != city2, "Should not be Equal");
}
-Brendan
Posted
Fri, Jul 9 2004 7:09 AM
by
Brendan Tompkins