Addition After a few years, and writing several equality comparers, my opinion has changed, such that I think it is better for the equality comparer to have a static member that holds the created comparer, instead of every user creating a new instance.
(original answer, with the adjustment mentioned above)
The solutions others gave, including the one that proposes to define a Comparison class for the strings, forgot to write a new GetHashCode
for your strings.
This means that your string can't be used in classes that depend upon GetHashCode
like Dictionary<T>
or HashSet<T>
.
See
Why is it important to override GetHashCode when Equals method is overridden?
Whenever you decide to change the concept of equality for any class, you should write an EqualityComparer
for that class. This makes sure that if according to your changed definition of equality to objects are considered equal, their GetHashCode
would return equal values.
public class NullStringComparer : EqualityComparer<string>
{
public static IEqualityComparer<string> NullEqualsEmptyComparer {get} = new NullStringComparer();
public override bool Equals(string x, string y)
{
// equal if string.Equals(x, y)
// or both StringIsNullOrEmpty
return String.Equals(x, y)
|| (String.IsNullOrEmpty(x) && String.IsNullOrEmpty(y));
}
public override int GetHashCode(string obj)
{
if (String.IsNullOrEmpty(obj))
return 0;
else
return obj.GetHashCode();
}
}
Usage:
public static void Main()
{
string x = null;
string y = String.Empty;
Console.WriteLine("Standard string comparison: {0}",
StringComparer.Ordinal.Equals(x, y));
Console.WriteLine($"My string comparison {0}",
NullStringComparer.NullEqualsEmpty.Equals(x, y));
// because according to the NullStringComparer x equals y
// GetHashCode should return the same value
int hashX = NullStringComparer.NullEqualsEmpty.GetHashCode(x);
int hashY = NullStringComparer.NullEqualsEmpty.GetHashCode(y);
Console.WriteLine($"hash X = {hashX}, hash Y = {hashY}");
}