A performance improved Hashtable with case-insensitive (string-only! based) key handling.
using System;
using System.Collections;
using System.Globalization;
using System.Runtime.Serialization;
using Spring.Util;
namespace Spring.Collections
{
/// <summary>
/// Provides a performance improved hashtable with case-insensitive (string-only! based) key handling.
/// </summary>
/// <author>Erich Eichinger</author>
[Serializable]
public class CaseInsensitiveHashtable : Hashtable
{
private readonly CultureInfo _culture;
/// <summary>
/// Creates a case-insensitive hashtable using <see cref="CultureInfo.CurrentCulture"/>.
/// </summary>
public CaseInsensitiveHashtable()
: this(null, CultureInfo.CurrentCulture)
{}
/// <summary>
/// Creates a case-insensitive hashtable using the given <see cref="CultureInfo"/>.
/// </summary>
/// <param name="culture">the <see cref="CultureInfo"/> to calculate the hashcode</param>
public CaseInsensitiveHashtable(CultureInfo culture)
: this(null, culture)
{}
/// <summary>
/// Creates a case-insensitive hashtable using the given <see cref="CultureInfo"/>, initially
/// populated with entries from another dictionary.
/// </summary>
/// <param name="d">the dictionary to copy entries from</param>
/// <param name="culture">the <see cref="CultureInfo"/> to calculate the hashcode</param>
public CaseInsensitiveHashtable(IDictionary d, CultureInfo culture)
{
AssertUtils.ArgumentNotNull(culture, "culture");
_culture = culture;
if (d != null)
{
IDictionaryEnumerator enumerator = d.GetEnumerator();
while (enumerator.MoveNext())
{
this.Add(enumerator.Key, enumerator.Value);
}
}
}
/// <summary>
/// Initializes a new, empty instance of the <see cref="T:System.Collections.Hashtable"></see> class that is serializable using the specified <see cref="T:System.Runtime.Serialization.SerializationInfo"></see> and <see cref="T:System.Runtime.Serialization.StreamingContext"></see> objects.
/// </summary>
/// <param name="context">A <see cref="T:System.Runtime.Serialization.StreamingContext"></see> object containing the source and destination of the serialized stream associated with the <see cref="T:System.Collections.Hashtable"></see>. </param>
/// <param name="info">A <see cref="T:System.Runtime.Serialization.SerializationInfo"></see> object containing the information required to serialize the <see cref="T:System.Collections.Hashtable"></see> object.</param>
/// <exception cref="T:System.ArgumentNullException">info is null. </exception>
protected CaseInsensitiveHashtable(SerializationInfo info, StreamingContext context) : base(info, context)
{
string cultureName = info.GetString("_cultureName");
_culture = new CultureInfo(cultureName);
AssertUtils.ArgumentNotNull(_culture, "Culture");
}
///<summary>
///Implements the <see cref="ISerializable"></see> interface and returns the data needed to serialize the <see cref="CaseInsensitiveHashtable"></see>.
///</summary>
///
///<param name="context">A <see cref="StreamingContext"></see> object containing the source and destination of the serialized stream associated with the <see cref="CaseInsensitiveHashtable"></see>. </param>
///<param name="info">A <see cref="SerializationInfo"></see> object containing the information required to serialize the <see cref="CaseInsensitiveHashtable"></see>. </param>
///<exception cref="System.ArgumentNullException">info is null. </exception>
public override void GetObjectData(SerializationInfo info, StreamingContext context)
{
base.GetObjectData(info, context);
info.AddValue("_cultureName", _culture.Name);
}
/// <summary>
/// Calculate the hashcode of the given string key, using the configured culture.
/// </summary>
/// <param name="key"></param>
/// <returns></returns>
protected override int GetHash(object key)
{
if (!(key is string)) return key.GetHashCode();
return _culture.TextInfo.ToLower((string) key).GetHashCode();
}
/// <summary>
/// Compares two keys
/// </summary>
protected override bool KeyEquals(object item, object key)
{
if (!(key is string))
{
return Equals(item,key);
}
return 0==_culture.CompareInfo.Compare((string) item, (string) key, CompareOptions.IgnoreCase);
}
/// <summary>
/// Creates a shallow copy of the current instance.
/// </summary>
public override object Clone()
{
return new CaseInsensitiveHashtable(this, _culture );
}
}
}