Try changing your GetHashCode to something that better distributes the values to reduce the number of collisions in the dictionary.
If your hash code is bad you're going to get the performance of a list rather than a hash-set. To show this consider a GetHashCode method that always returns 0 for any object.
Trying to put that into a Dictionary will force the dictionary to put all the items into the same bucket (http://en.wikipedia.org/wiki/Hash_table#Hashing), yielding linear search time rather than close to random access time for a perfect hash.
The math behind a clever hash is beyond me, for integer only structs I usually use something similar to the example below.
Consider this implementation of your Coordinate_t struct;
struct Coordinate_t
{
int x, y, z;
public Coordinate_t(int x, int y, int z) {
this.x = x;
this.y = y;
this.z = z;
}
public override int GetHashCode() {
uint h = 0x811c9dc5;
h = (h ^ (uint)x) * 0x01000193;
h = (h ^ (uint)y) * 0x01000193;
h = (h ^ (uint)z) * 0x01000193;
return (int)h;
}
}
If you comment out the GetHashCode you'll see a massive change in performance when using a dictionary.
Test application
struct Coordinate_t {
int x, y, z;
public Coordinate_t(int x, int y, int z) {
this.x = x;
this.y = y;
this.z = z;
}
// Uncomment this to make it go faster
//public override int GetHashCode() {
// uint h = 0x811c9dc5;
// h = (h ^ (uint)x) * 0x01000193;
// h = (h ^ (uint)y) * 0x01000193;
// h = (h ^ (uint)z) * 0x01000193;
// return (int)h;
//}
}
class Program {
static void Main(string[] args) {
var tiles = new Dictionary<Coordinate_t, string>();
var sw = new Stopwatch();
sw.Start();
const int count = 100;
for (var x = 0; x < count; ++x)
for (var y = 0; y < count; ++y)
for (var z = 0; z < count; ++z)
tiles[new Coordinate_t(x, y, z)] = String.Format("{0}.{1}.{2}", x, y, z);
sw.Stop();
Console.WriteLine("Add took {0}", sw.Elapsed);
sw.Reset();
sw.Start();
for (var x = 0; x < count; ++x)
for (var y = 0; y < count; ++y)
for (var z = 0; z < count; ++z)
{
var expected = String.Format("{0}.{1}.{2}", x, y, z);
if (tiles[new Coordinate_t(x, y, z)] != expected)
{
throw new Exception("Something is super-broken!");
}
}
sw.Stop();
Console.WriteLine("Get took {0}", sw.Elapsed);
}
}