Please let me know of any eventual bugs you might find.
Here are a few things that jumped into my eyes:
* try/catch:
try
{
return _host [_keys [_i]];
}
catch (System.IndexOutOfRangeException e)
{
throw e;
}
Could be written just as:
return _host [_keys [_i]];
There is really no good reason to catch an rethrow that exception, is
there?
If you need to do some work on the way out in a callstack, you can use
finally, or when you need to use the Exception (for logging for example),
using "throw" instead of "throw e" preserves the original stacktrace.
* Enumerator:
You define enumeration to be sorted, there is no reason for that, the
basic iteration of hashtables or dictionaries are not guranteed to be
sorted, sorting is expensive (in this context where operations are O(1)

and requires you to spen O(capacity) memory, which is pretty much for
large hashed.
To do sorted iteration, the user can easily do:
int[] keys = new int[dict.Count]
dict.keys.CopyTo(keys, 0);
foreach ( int key in keys ) {
object val = dict[key];
}
or you can define a class SortedCollection that accepts an ICollection and
provides sorted Enumeration.
* indexing:
why do your do "& int.MaxValue"?
int i = (key & int.MaxValue) % _slots.Length;
Rather than
int index = (uint)key % _slots.Length;
It's less expensive, and doesn't disregard the most-significant bit of
your key
* .Values
Return a new instance of ICollection that simply iterates the hashtable,
returning only the keys. This saves a lot of memory.
If the user want's an array he can do dict.Values.CopyTo(array, index).
* int this[int key] { set }
* Add(key, value, overwrite)
Why do you accept ref's to key and value?
* Clear:
use the System.Array methods for clearing an array, or simple assign a
new array to _slots