"ABC" == "abc"
Depending on the context, case insensitive equality checking may be required. Also precision on floating point value comparisons.An interesting approach to this in C# (and other languages) is to use ad-hoc polymorphism:
public interface Eq<A>
{
bool AreEqual(A x, A y);
}
public struct EqInt : Eq<int>
{
public bool AreEqual(int x, int y) => x == y;
}
public struct EqDbl : Eq<double>
{
public bool AreEqual(double x, double y) => Math.Abs(x - y) < 0.00001;
}
public struct EqStringExact : Eq<string>
{
public bool AreEqual(string x, string y) => x == y;
}
public struct EqStringIgnoreCase : Eq<String>
{
public bool AreEqual(string x, string y) =>
String.Equals(x, y, StringComparison.CurrentCultureIgnoreCase);
}
public static class GenericCode
{
public static A UseFirstIfEqual<EQ, A>(A fst, A snd)
where EQ : struct, Eq<A> =>
default(EQ).AreEqual(fst, snd)
? fst
: snd;
}
GenericCode.UseFirstIfEqual<EqInt, int>(10, 10); // 10
GenericCode.UseFirstIfEqual<EqInt, int>(10, 20); // 20
GenericCode.UseFirstIfEqual<EqDbl, int>(10.0, 10.0); // 10.0
GenericCode.UseFirstIfEqual<EqDbl, int>(10.0, 20.0); // 20.0
GenericCode.UseFirstIfEqual<EqStringExact, string>("ABC", "abc"); // "abc"
GenericCode.UseFirstIfEqual<EqStringIgnoreCase, string>("ABC", "abc"); // "ABC"
It's slightly more novel than the interface approach, and allows for retrospective equality behaviours to be authored for a sealed type, and importantly, for the selection of the most appropriate equality operation for any particular context.I don't have a compiler to hand, so apologies for any errors!