Case insensitive string to replace custom comparers In some solutions I use case-insensitive strings a lot and so far I've been always writing custom collections or using custom comparers to support them. This is usually a lot of work and a lot of testing so I thought what if the string was case-insensitive instead? 

The implementation is really simple because the CaseInsensitiveString is just a wrapper for a string that is using the StringComparer.OrdinalIgnoreCase comparer internally. Can you think of any improvements? I use it for hash-sets or dictionaries or anything else that might require case insensitive strings.

public class CaseInsensitiveString : IEquatable&lt;CaseInsensitiveString&gt;, IEquatable&lt;string&gt;
{
    private readonly string value;

    public CaseInsensitiveString() { }

    public CaseInsensitiveString(string value)
    {
        this.value = value;
    }

    private CaseInsensitiveString(CaseInsensitiveString other)
    {
        value = other?.value;
    }

    public static CaseInsensitiveString Empty =&gt; new CaseInsensitiveString(string.Empty);

    public override int GetHashCode()
    {
        return StringComparer.OrdinalIgnoreCase.GetHashCode(value);
    }

    public override bool Equals(object obj)
    {
        return
            (obj is CaseInsensitiveString cis &amp;&amp; Equals(cis)) ||
            (obj is string s &amp;&amp; Equals(s));
    }

    public bool Equals(CaseInsensitiveString other)
    {
        if (ReferenceEquals(other, null)) return false;
        return ReferenceEquals(this, other) || Equals(other.value);
    }

    public bool Equals(string other)
    {
        return StringComparer.OrdinalIgnoreCase.Equals(value, other);
    }

    public static implicit operator string(CaseInsensitiveString obj) =&gt; obj.value;

    public static implicit operator CaseInsensitiveString(string value) =&gt; new CaseInsensitiveString(value);

    public static bool operator ==(CaseInsensitiveString left, CaseInsensitiveString right) =&gt; new CaseInsensitiveString(left).Equals(right);

    public static bool operator !=(CaseInsensitiveString left, CaseInsensitiveString right) =&gt; !(left == right);
}


Example usage:

var set = new HashSet&lt;CaseInsensitiveString&gt;();
set.Add("foo").Dump(); // true
set.Add("fOo").Dump(); // false

var s = (CaseInsensitiveString)"foo";
(s == "foo").Dump(); // true
(s == "fOo").Dump(); // true
Creating a throw-away object just to perform == comparison is ugly,
and likely inefficient:


public static bool operator ==(CaseInsensitiveString left, CaseInsensitiveString right) =&gt; new CaseInsensitiveString(left).Equals(right);



I suspect you wanted to avoid a tedious null-check, but I don't think you have a choice:

public static bool operator ==(CaseInsensitiveString left, CaseInsensitiveString right) =&gt; !ReferenceEquals(left, null) &amp;&amp; left.Equals(right);


But there's a more serious problem.
As it stands, two null instances of CaseInsensitiveString are not equal, and it should be.