Declare iterator variable in `for` loop

There is no performance advantage to reusing variables like this--it
only increases the likelihood of the variable being misused.
Make _hashCode readonly

It's good practice to only use read-only fields in the GetHashCode()
method. Explicitly making the field `readonly` will help avoid bugs in
the future.

I also changed the `CreateHashCode()` method to return a value instead
of modifying the `_hashCode` field. This helps to solidify the notion
that the `MetadataCacheKey` class is immutable.
Missed a return statement
Made `MetadataCache` thread-safe

Previously, if multiple concurrent calls were made to `GetWorkspace()`,
it was possible to end up with odd behavior from race conditions. By
using a `ConcurrentDictionary`, we can avoid this problem, and simplify
the code at the same time.