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)
{
r开发者_JAVA技巧eturn 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?
You don't need to create such a type in the first place.
Instead, you should use the StringComparer
class.
For example:
var dict = new Dictionary<String, string>(StringComparer.OrdinalIgnoreCase);
dict["Help"] = "thanks!";
Assert.AreEqual("thanks!", dict["hELP"]);
Or
List<String> list = new List<String>();
list.Add("help");
Assert.IsTrue(list.Contains("Help", StringComparer.OrdinalIgnoreCase));
Also note that it shouldn't be named IString
; only interfaces should begin with I
.
To answer your question, no; that's impossible.
No there is not. The String.Equals(object)
method has a hard dependency on the provided value being of the type String
. It does a CLR type check which does not consider any user defined conversions or functions and hence will only work with an instance of System.String
精彩评论