比较相同泛型类型的两个实例的最佳(最简洁和最佳)方法是什么,以便比较引用类型的身份(相同的对象,所以不调用Equals
)和值类型的值相等。
目前我这样做:
static bool IdentityEquals<T>(T x, T y)
{
return typeof(T).IsValueType
? EqualityComparer<T>.Default.Equals(x, y)
: ReferenceEquals(x, y);
}
您应该能够仅object.Equals
用于值类型:
return typeof(T).IsValueType
? object.Equals(x, y)
: ReferenceEquals(x, y);
在您感兴趣的类型上实现IEquatable<T>以及 object.Equals( )和object.GetHashCode()的覆盖,或者为您的类型使用者提供IEqualityComparer<T>的实例。
DOT NET没有实现你对平等的定义,因为那样它就不是我的,也不是 Fred 的。相反,它为您提供了工具来准确地构建您需要的东西,而无需踩到我的脚趾或咬住我需要构建的东西。
不幸的是,.NET 只定义了一种标准虚拟Equals
方法和一种GetHashCode
方法,即使这样的问题可能会提出两个逻辑问题(如果假设X
并且Y
是相同类型的变量,那么问题是最简单的):
假设X
并Y
持有对int[1]
当前包含值 42 的两个类型对象的引用。一些外部代码持有对与 相同的实例的引用Y
,并且即将增加它。如果要更改X
为指向与 相同的实例Y
,那将更改 的未来值X[0]
。
另一方面,假设两个对象每个都有一个私有字段,每个对象都拥有一个存在于宇宙中任何地方的对自己的引用,int[1]
并且都持有并将始终持有值 42,并且两者都没有导致RuntimeHelpers.GetHashCode()
被调用那个例子。即使int[1]
是可变类型,上述两个实例也应该被认为是等效的,因为将第一个的“所有引用”[即唯一的引用]与对第二个的所有引用交换对程序行为没有影响。然而,如果一个数组持有 23 而另一个持有 27,则交换引用将交换哪个对象持有对 23 的引用,而哪个对象持有 27。
请注意,如果添加“不同类型的对象不能等价,因为它们的GetType()
方法必然会表现不同”的陈述,那么对于任何类类型的对象,上述两个问题都可以得到有意义且明确的回答,而第二个问题对于任何类类型的对象都可以得到有意义的回答。任何值类型。答案将构成对等价和价值平等的有意义的定义。.NET 覆盖的正常行为Equals
倾向于让引用类型回答第一个问题(代码更可能对它感兴趣),让值类型回答第二个问题(因为第一个问题对他们来说毫无意义)。由于听起来默认行为是您想要的,也许您可以描述是否存在某些情况不是这样?
[注意:一些 .NET 类型,例如以 loosy-goosy 方式Decimal
定义Equals
;上面的两个问题最好用通用的虚拟方法来回答]。