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<CaseInsensitiveString>, IEquatable<string>
{
private readonly string value;
public CaseInsensitiveString() { }
public CaseInsensitiveString(string value)
{
this.value = value;
}
private CaseInsensitiveString(CaseInsensitiveString other)
{
value = other?.value;
}
public static CaseInsensitiveString Empty => new CaseInsensitiveString(string.Empty);
public override int GetHashCode()
{
return StringComparer.OrdinalIgnoreCase.GetHashCode(value);
}
public override bool Equals(object obj)
{
return
(obj is CaseInsensitiveString cis && Equals(cis)) ||
(obj is string s && 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) => obj.value;
public static implicit operator CaseInsensitiveString(string value) => new CaseInsensitiveString(value);
public static bool operator ==(CaseInsensitiveString left, CaseInsensitiveString right) => new CaseInsensitiveString(left).Equals(right);
public static bool operator !=(CaseInsensitiveString left, CaseInsensitiveString right) => !(left == right);
}
Example usage:
var set = new HashSet<CaseInsensitiveString>();
set.Add("foo").Dump(); // true
set.Add("fOo").Dump(); // false
var s = (CaseInsensitiveString)"foo";
(s == "foo").Dump(); // true
(s == "fOo").Dump(); // true
public ISet<string> Something { get; set; }
\$\endgroup\$ToString
but yes, it's my full class but this one method. \$\endgroup\$