IEquatable<T>.Equals
应该与Object.Equals
覆盖一致。我不确定直接使用IEquatable<T>
直接提供任何价值。
在我看来,您只是想确保装箱的对象使用未装箱的值进行相等测试。你应该能够用这样的 equals 做大部分你想做的事情:
private static bool Equals<T1, T2>(T1 first, T2 second)
{
// if either are boxed, try Equals with unboxed values (dynamic)
if (typeof(T2) == typeof(object) && second.GetType().IsValueType)
{
dynamic dsec = second;
if (typeof(T1) == typeof(object) && second.GetType().IsValueType)
{
dynamic dfir = first;
return Equals(dfir, dsec);
}
return Equals(first, dsec);
}
if (typeof(T1) == typeof(object) && second.GetType().IsValueType)
{
dynamic dfir = first;
Equals<dynamic, T2>(dfir, second);
}
// neither are boxed, just fall back to their Equals overrides...
var t = Object.Equals(first, second);
return t;
}
Enumerable.Intersect
并且Except
只使用相同类型的集合,所以如果类型是Object
它应该做你想要的。
更新:
值类型不能从基类派生。它们唯一的共同基础永远只有对象,这意味着如果你想比较两种不同的值类型,而不是专门使用一种知道你想比较的两种类型的方法,你总是必须装箱至少一个值——哪个Enumerable.Intersect
和Except
不'无论如何都接受。所以不写不同的方法是不可能的。
更新 2:
假设如果两种类型不能在彼此之间(或一种到另一种)之间转换,这意味着它们永远不会相等,这是一个糟糕的假设。例如:
public struct One
{
public int Value;
public override int GetHashCode()
{
return Value.GetHashCode();
}
}
public struct Two
{
public int Value;
public override bool Equals(object obj)
{
if (obj is Two) return this == (Two)obj;
if (obj is One) return this.Equals((One)obj);
return base.Equals(obj);
}
public bool Equals(One one)
{
return one.Value == Value;
}
public static bool operator==(Two one, Two two)
{
return one.Value == two.Value;
}
public static bool operator !=(Two one, Two two)
{
return !(one == two);
}
public override int GetHashCode()
{
return Value.GetHashCode();
}
}
// ...
Console.WriteLine(two.Equals(one));
Console.WriteLine(two.Equals((Object)one));
Console.WriteLine(two.GetType().IsAssignableFrom(one.GetType()) || one.GetType().IsAssignableFrom(two.GetType()));
结果为真、真和假。因此,显然两个对象可以“相等”,但不能相互转换。