views:

1511

answers:

4

Wondering if this is possible.

We have an 3rd Party library that contains identification information about users...

The main interaction with the library is through a HashTable which is keyed with a string, and returns an Object Graph of information for that key.

The problem is, the key is obviously Case Sensitive, but what we get from the users browser doesn't necessarily match the case... (We often get the key fully lowercase'd)

I'm wondering if it's possible to do a case Insensitive key search against a hashtable.

e.g.

Hashtable ht = new Hashtable();
ht.Add("MyKey", "Details");

string result = ht["MyKey"];
string result = ht["MYKEY"];
string result = ht["mykey"];

On the off chance we could submit a support ticket to the company to add this functionality, are there any other DataStructures (i.e. the new generic collections/dictionaries) that support this functionality

Lastly, would it be possible to override the System.String GetHashCode() method, to make all case invariant strings return the same hashcode... e.g. I'm thinking this is a no goer as string is a sealed class

Cheers if anyone has any suggestions

+4  A: 

With a dictionary:

new Dictionary<string, string>(StringComparer.OrdinalIgnoreCase);

but simpler, I believe StringDictionary is case-insensitive too:

    StringDictionary ht = new StringDictionary();
    ht.Add("MyKey", "Details");

    string result1 = ht["MyKey"];
    string result2 = ht["MYKEY"];
    string result3 = ht["mykey"];
Marc Gravell
Cheers Marc. And cheers to the others for pointing out the IEqualityOperator overloads... Unfortunately, I've no access to the internals of the library or the construction of the Hashtable... I only discovered the implementation by using Reflector to poke around inside it. I think I'll log a support ticket with the company and ask them if it can be added as a "Feature"
Eoin Campbell
+1  A: 

You can supply an case-insensitive IEqualityComparer to the HashTable constructor, but this requires that you can influence the HashTable construction in the 3rd party library.

If you fill the hash table from your code, you could normalize the keys on insertion and retrieve normalized keys again.

If you are unable to influence the content of the hash table, but you know the structure of the keys, you could correct the user input before accessing the hash table.

Daniel Brückner
+4  A: 

Code to make the hashtable comparisons case-insensitive

For 2.0, 3.0, 3.5

Hashtable ht = new Hashtable(StringComparer.InvariantCultureIgnoreCase);

You can get info on InvariantCultureIgnoreCase vs. OrdinalIgnoreCase on this SO link

OR

Hashtable ht = System.Collections.Specialized.CollectionsUtil.CreateCaseInsensitiveHashtable();

Because case-insensitive dictionary collection is such a common use, the .NET Framework has a CollectionUtil class that supports creating Hashtable and SortedList objects that are case insensitive. Use by calling CreateCaseInsensitiveHashtable or CreateCaseInsensitiveSortedList.

For .Net 1.0 (I am not sure if 1.0 supports StringComparer)

public class InsensitiveComparer : IEqualityComparer
{
    CaseInsensitiveComparer _comparer = new CaseInsensitiveComparer();
    public int GetHashCode(object obj)
    {
        return obj.ToString().ToLowerInvariant().GetHashCode();
    }

    public new bool Equals(object x, object y)
    {
        if (_comparer.Compare(x, y) == 0)
        {
            return true;
        }

        else
       {
           return false;
       }
    }
}

Hashtable dehash = new Hashtable(new InsensitiveComparer());
Rashmi Pandit
The StringComparer class already provides case-insensitive comparers - no need to implement your own.
Daniel Brückner
Thanks Daniel. I have edited my response.
Rashmi Pandit
This is just an FYI: I found out that StringDictionary keys are case insensitive by default. But both the key and value must be strings.
Rashmi Pandit
Also you can use CreateCaseInsensitiveHashtable. Edited my response to reflect the usage.
Rashmi Pandit
+1  A: 

This isn't a very efficient way, but you could always take the hashtable and make a StringDictionary from it:

Hashtable ht = new Hashtable();
ht.Add("FOO", "bar");

StringDictionary dict = new StringDictionary();

foreach(string key in ht.Keys)
    dict.Add(key, ht[key].ToString());

string result = dict["foo"]; // Assigns "bar" to result
Rytmis
+1 This is nice idea. (But fails on "FOO" and "foo" in the hash table.)
Daniel Brückner
Well, using the indexer instead of the Add method would prevent an exception, and wouldn't any solution have the same problem, if the original Hashtable has multiple keys that differ by case only?
Rytmis