I created a C# struct which can generically handle case insensitive string comparisons, transparently. So for example:
List<IString> list = new List<IString>(); list.Add("help"); Assert.IsTrue(list.Contains("Help")); or
Dictionary<IString, string> dict = new Dictionary<IString, string>(); dict["Help"] = "thanks!"; Assert.AreEqual("thanks!", dict["hELP"]); But the one thing I can't figure out (and maybe it's not possible), is how to get class string to play nicely in .Equals(object):
IString A1 = "A"; string A2 = "a"; Assert.AreEqual(A1, A2, "This passes"); Assert.AreEqual(A2, A1, "This fails"); Here's the code:
using System; using System.Collections.Generic; namespace Util { /// <summary> /// Case insensitive wrapper for the string class /// </summary> public struct IString : IComparer<IString>, IComparable, IComparable<IString>, IComparable<string>, IEquatable<string>, IEquatable<IString> { private const StringComparison icase = StringComparison.OrdinalIgnoreCase; public readonly string Value; public IString(string Value) { this.Value = Value; } public bool Equals(string Other) { return string.Equals(Value, Other, icase); } public bool Equals(IString Other) { return string.Equals(Value, Other.Value, icase); } public override bool Equals(object obj) { if (obj is IString || obj is string) { return string.Equals(Value, obj.ToString(), icase); } else { return false; } } public int IndexOf(string Other) { return Other.IndexOf(Other, icase); } public bool Contains(string Other) { return IndexOf(Other) >= 0; } public override int GetHashCode() { if (Value == null) return 0; else return StringComparer.OrdinalIgnoreCase.GetHashCode(Value); } public override string ToString() { return Value; } public int Compare(IString x, IString y) { return string.Compare(x.Value, y.Value, icase); } public int Compare(string x, string y) { return string.Compare(x, y, icase); } public int CompareTo(object obj) { if (obj is IString) return Compare(this, (IString)obj); else if (obj is string) return Compare(Value, (string)obj); else if (Value != null) return Value.CompareTo(obj); else return -1; } public int CompareTo(IString other) { return Compare(this, other); } public int CompareTo(string other) { return Compare(Value, other); } public static implicit operator string(IString From) { return From.Value; } public static implicit operator IString(string From) { return new IString(From); } #region IString to IString operators public static bool operator ==(IString Str1, IString Str2) { return string.Equals(Str1.Value, Str2.Value, icase); } public static bool operator !=(IString Str1, IString Str2) { return !string.Equals(Str1.Value, Str2.Value, icase); } public static IString operator +(IString Str1, IString Str2) { return (IString)(Str1.Value + Str2.Value); } public static bool operator >(IString Str1, IString Str2) { return Str1.CompareTo(Str2) > 0; } public static bool operator >=(IString Str1, IString Str2) { return Str1.CompareTo(Str2) >= 0; } public static bool operator <(IString Str1, IString Str2) { return Str1.CompareTo(Str2) < 0; } public static bool operator <=(IString Str1, IString Str2) { return Str1.CompareTo(Str2) <= 0; } #endregion IString to IString operators #region string to IString operators public static bool operator ==(string Str1, IString Str2) { return string.Equals(Str1, Str2.Value, icase); } public static bool operator !=(string Str1, IString Str2) { return !string.Equals(Str1, Str2.Value, icase); } public static IString operator +(string Str1, IString Str2) { return (IString)(Str1 + Str2.Value); } public static bool operator >(string Str1, IString Str2) { return Str2.CompareTo(Str1) < 0; } public static bool operator >=(string Str1, IString Str2) { return Str2.CompareTo(Str1) <= 0; } public static bool operator <(string Str1, IString Str2) { return Str2.CompareTo(Str1) > 0; } public static bool operator <=(string Str1, IString Str2) { return Str2.CompareTo(Str1) >= 0; } #endregion string to IString operators #region IString to string operators public static bool operator ==(IString Str1, string Str2) { return string.Equals(Str1.Value, Str2, icase); } public static bool operator !=(IString Str1, string Str2) { return !string.Equals(Str1.Value, Str2, icase); } public static IString operator +(IString Str1, string Str2) { return (IString)(Str1.Value + Str2); } public static bool operator >(IString Str1, string Str2) { return Str1.CompareTo(Str2) > 0; } public static bool operator >=(IString Str1, string Str2) { return Str1.CompareTo(Str2) >= 0; } public static bool operator <(IString Str1, string Str2) { return Str1.CompareTo(Str2) < 0; } public static bool operator <=(IString Str1, string Str2) { return Str1.CompareTo(Str2) <= 0; } #endregion IString to string operators } } Is there any way to get string.Equal(object) to actually deal with IString as a string?
OrdinalIgnoreCaseinstead ofInvariantCultureIgnoreCase; it's faster and more secure.return StringComparer.OrdinalIgnoreCase.GetHashCode(Value);.InsensitiveStringorCaselessStringorUncasedString?