开发者

Case insensitive compare string to non-string

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

0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜