如何以最简洁和最优的方式比较两个相同泛型类型的实例,使得引用类型比较其身份(同一对象,因此不调用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>
,这通常可以避免在使用EqualityComparer<T>
时进行装箱。 - D Stanley不幸的是,.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
重写的正常行为倾向于让引用类型回答第一个问题(代码更可能对其感兴趣),并让值类型回答第二个问题(因为第一个问题对它们来说是无意义的)。由于听起来默认行为是您想要的,也许您可以描述一下是否存在某种情况,其中它不是默认行为?Decimal
)以松散的方式定义Equals
;上述两个问题将是通用虚拟方法所需回答的好问题]。要么在您感兴趣的类型上实现IEquatable<T>,并重写object.Equals()和object.GetHashCode(),要么为您的类型使用者提供IEqualityComparer<T>的实例。
DOT NET不会实现您定义的相等性,因为那样它就不会是我的,也不会是街上的Fred的。相反,它为您提供了构建所需工具的机会,而不会妨碍我构建所需的内容。