Table of Contents

Class ByValueEqualityComparer

Namespace
Nerdbank.MessagePack
Assembly
Nerdbank.MessagePack.dll

Provides deep by-value implementations of IEqualityComparer<T> for arbitrary data types.

public static class ByValueEqualityComparer
Inheritance
ByValueEqualityComparer
Inherited Members

Remarks

The deep walking of the object graph for deep by-value equality and hashing is based on the same GenerateShapeAttribute that is used to generate MessagePack serializers. The implementation therefore considers all the same properties for equality and hashing that would be included in a serialized copy.

This implementation is not suitable for all types. Specifically, it is not suitable for types that have multiple memory representations that are considered equal. An invariant for IEqualityComparer<T> behavior must be that if x.Equals(y) then x.GetHashCode() == y.GetHashCode(). For an auto-generated implementation of these methods for arbitrary types such as this, no specialization for multiple values that are considered equal is possible.

For example, a double value has distinct memory representations for 0.0 and -0.0, yet these two values are considered equal and must have the same hash code. In this case and for several other common data types included with .NET, special consideration is built-in for correct operation. But this cannot be done automatically for any user-defined types.

When using user-defined types for which this implementation is inappropriate, a custom implementation of IEqualityComparer<T> may be used if the type is used directly. But if the type is referenced in a type reference graph such that is used for by-value comparison, implementing IDeepSecureEqualityComparer<T> on that type will allow the type to take control of just its contribution to the hash code and equality comparison.

Types that define no (public or opted in) properties and do not implement IDeepSecureEqualityComparer<T> will throw a NotSupportedException when attempting to create an equality comparer.

This implementation should only be used for acyclic graphs, since cyclic graphs will cause a StackOverflowException while performing the comparison.

Another consideration is that types used as keys in collections should generally not have a changing hash code or the collections internal data structures may become corrupted by a key that is stored in the wrong hash bucket. Keys should generally be immutable to prevent this, or at least immutable in the elements that contribute to the hash code. In an automated equality comparer such as the one produced by this class, all public properties contribute to the hash code, even if they are mutable. Care should therefore be taken to not mutate properties on objects used as keys in collections.

The values are compared by their declared types rather than polymorphism. If some type has a property of type Foo, and the actual value at runtime derives from Foo, only the properties on Foo will be considered. If between two object graphs being equality checked, their runtime types do not match, the equality check will return false.

Methods

GetDefault<T>()

Gets a deep by-value equality comparer for the type T, without hash collision resistance.

public static IEqualityComparer<T> GetDefault<T>() where T : IShapeable<T>

Returns

IEqualityComparer<T>

The equality comparer.

Type Parameters

T

The type to be compared.

Remarks

See the remarks on the class for important notes about correctness of this implementation.

GetDefault<T>(ITypeShape<T>)

Gets a deep by-value equality comparer for the type T, without hash collision resistance.

public static IEqualityComparer<T> GetDefault<T>(ITypeShape<T> shape)

Parameters

shape ITypeShape<T>

The type shape.

Returns

IEqualityComparer<T>

The equality comparer.

Type Parameters

T

The type to be compared.

Remarks

See the remarks on the class for important notes about correctness of this implementation.

GetDefault<T>(ITypeShapeProvider)

Gets a deep by-value equality comparer for the type T, without hash collision resistance.

public static IEqualityComparer<T> GetDefault<T>(ITypeShapeProvider provider)

Parameters

provider ITypeShapeProvider
The shape provider of T. This will typically be obtained by calling the ShapeProvider static property on a witness class (a class on which GenerateShapeAttribute<T> has been applied).

Returns

IEqualityComparer<T>

The equality comparer.

Type Parameters

T

The type to be compared.

Remarks

See the remarks on the class for important notes about correctness of this implementation.

GetDefault<T, TProvider>()

Gets a deep by-value equality comparer for the type T, without hash collision resistance.

public static IEqualityComparer<T> GetDefault<T, TProvider>() where TProvider : IShapeable<T>

Returns

IEqualityComparer<T>

An equality comparer.

Type Parameters

T

The type to be compared.

TProvider

The witness type that provides the IShapeable<T> for T.

Remarks

See the remarks on the class for important notes about correctness of this implementation.

GetHashResistant<T>()

Gets a deep by-value equality comparer for the type T, with hash collision resistance.

public static IEqualityComparer<T> GetHashResistant<T>() where T : IShapeable<T>

Returns

IEqualityComparer<T>

The equality comparer.

Type Parameters

T

The type to be compared.

Remarks

See the remarks on the class for important notes about correctness of this implementation.

GetHashResistant<T>(ITypeShape<T>)

Gets a deep by-value equality comparer for the type T, with hash collision resistance.

public static IEqualityComparer<T> GetHashResistant<T>(ITypeShape<T> shape)

Parameters

shape ITypeShape<T>

The type shape.

Returns

IEqualityComparer<T>

The equality comparer.

Type Parameters

T

The type to be compared.

Remarks

See the remarks on the class for important notes about correctness of this implementation.

GetHashResistant<T>(ITypeShapeProvider)

Gets a deep by-value equality comparer for the type T, with hash collision resistance.

public static IEqualityComparer<T> GetHashResistant<T>(ITypeShapeProvider provider)

Parameters

provider ITypeShapeProvider
The shape provider of T. This will typically be obtained by calling the ShapeProvider static property on a witness class (a class on which GenerateShapeAttribute<T> has been applied).

Returns

IEqualityComparer<T>

The equality comparer.

Type Parameters

T

The type to be compared.

Remarks

See the remarks on the class for important notes about correctness of this implementation.

GetHashResistant<T, TProvider>()

Gets a deep by-value equality comparer for the type T, with hash collision resistance.

public static IEqualityComparer<T> GetHashResistant<T, TProvider>() where TProvider : IShapeable<T>

Returns

IEqualityComparer<T>

An equality comparer.

Type Parameters

T

The type to be compared.

TProvider

The witness type that provides the IShapeable<T> for T.

Remarks

See the remarks on the class for important notes about correctness of this implementation.