Search code examples
c#case-insensitive

StringComparer.InvariantCultureIgnoreCase for char


How can I compare char using an arbitrary comparer?

I've tried using StringComparer but it only works if I convert the char to string.

var cmp = StringComparer.InvariantCultureIgnoreCase;
char a = 'a';
char A = 'A';
cmp.Equals(a.ToString(), A.ToString()) //true - works
cmp.Equals(a, A) //false, working on the .Equals(object,object)

My guess would be that there is a call to whatever StringComparer is using to compare the characters.


Solution

  • If you look at the source code for the StringComparer class, you can see what's happening. The InvariantCultureIgnoreCase member creates a new instance of the CultureAwareComparer class:

    private static readonly StringComparer _invariantCultureIgnoreCase = new CultureAwareComparer(CultureInfo.InvariantCulture, true);
    

    The CultureAwareComparer class implements the Equals(String, String) method and takes the culture and case options into account. It does not implement Equals(Object, Object), which is defined in the StringComparer base class and called instead when you're trying to compare 2 chars. The definition of StringComparer.Equals(Object, Object) is:

    public new bool Equals(Object x, Object y) {
        if (x == y) return true;
        if (x == null || y == null) return false;
        String sa = x as String;
        if (sa != null) {
            String sb = y as String;
            if( sb != null) {
                return Equals(sa, sb);
            }
        }
        return x.Equals(y);
    }
    

    As you can see, it converts both chars to String and then calls the String.Equals(String, String) method, the standard String comparison that doesn't take culture or case into account. So, if you want to compare chars with a StringComparer culture, you'll have to convert them to string first.