Do the keys of a Dictionary need to be comparable with equality?
For example
Class mytype
{
public bool equals(mytype other)
{
return ...;
}
}
In my case they won't be equal unless they are the same instance.
If I need to implement equality should I have a large numeric value that increments with every new instance of mytype created?
If your classes are only equal if they are same instance, then you don't need to do anything to use them in a Dictionary. Classes (reference types) are considered equal if and only if the refer to the same object.
From the documentation of GetHashCode
For derived classes of Object, the GetHashCode method can delegate to the Object.GetHashCode implementation, if and only if that derived class defines value equality to be reference equality and the type is not a value type.
Which seems to be true in your case. As a rule of thumb, if you override Equal you need to override GetHashCode as well but this is not necessary in your case as the default is what you are looking for.
By default, equality is based on the instance. Two separate instances are never equal. You can only change that by providing your own Equals method.
Only if they are being used as a key and you don't want to base equivalence on the instance of the object itself. If you only want references to the exact same instance to be equivalent, you are fine and need do nothing, but if you are using your type as a key, and you want "equivalent" instances to be considered equal, your class must implement Equals() and GetHashCode().
If your custom type is being stored as a value, and not used as a key, this is not necessary, of course. For example, in this case MyType does not need to override Equals() or GetHashCode() because it is only used as a value, and not as the storage key.
Dictionary<string, MyType> x;
However in this case:
Dictionary<MyType, string> x;
Your custom type is the key, and thus it would need to override Equals() and GetHashCode(). The GetHashCode() is used to determine which location it hashes to, and the Equals() is used to resolve collisions on the hash code (among other things).
You'd need to override the same two methods when dealing with many LINQ queries as well. Alternatively, you can provide a standalone IEqualityComparer apart from your class to determine if two instances are equivalent.
See the EqualityComparer.Default<T> property. This is how the dictionary obtains an equality comparer if you don't supply it with one.
This returns an equality comparer based on the type & capabilities of T.
For example, if T extends IEquatable, EqualityComparer.Default will return an equality comparer instance that uses the IEquatable interface. Otherwise it will return an equality comparer instance that uses the Object.Equals method.
The Object.Equals method, by default for reference types, uses reference equality (Object.ReferenceEquals) unless you override it with a custom comparison.
The Object.Equals method, by default for value types, uses reflection to compare the fields of the struct for equality*. Reflection being slow, this is why it's always recommended to override Equals in value types.
* unless it's a blittable value type in which case the raw bits are compared.
No, there are no type constraints on Dictionary<TKey, TValue>
Related
I've got an entity that I build, I take an instantiated entity and a modified entity. This allows me to hold the initial data, to compare against the modified data. The question, is what would be the ideal approach? Should I implement IEquatable as an override on Object.Equals or implement ICompare? My original implementation was:
var properties = typeof(TEntity).GetProperties();
foreach(var property in properties)
{
var initialEntity = original.GetType().GetProperty(property.Name).GetValue(original, null);
var modifiedEntity = userChange.GetType().GetProperty(property.Name).GetValue(userChange, null);
if(initialEntity.Equals(modifiedEntity) == false && !ignore.Contains(property.Name))
{
// Do Something
}
}
My understanding was that it would return a boolean, also in this instance it would compare on Value Equality, I'm assuming though it is comparing based on reference equality.
Because it never distinguishes, it remains equal under all circumstances.
The simplest answer:
If you need to test equality, implement IEquatable<T> and override Equals() and GetHashCode()
If you need to sort objects, implement IComparable<T>
The default implementation of Object.Equals() determines if the memory location used by one object is the same as another object. This is essentially what Object.ReferenceEquals(obj1, obj2) does, but dot net needs you to tell it how to determine if two objects you create are equivalent.
Additionally, the default implementation of Object.GetHashCode() is the 32 bit address (or portion of an address) of where the object is located in memory. Unless you override it to generate a hash code that is a function of everything you compared in your Equals() method, you will get unexpected results when you attempt to store it in a hash set or use it as a dictionary key.
You may need to implement both, but it looks like in your case IEquatable<T> is the most pressing need.
Explanation:
Equals() compares the values of two objects.
ReferenceEquals() compares their references.
For reference types operator== by default compares references, while for value types it performs (AFAIK) the equivalent of Equals() using reflection.
So. I have a situation where I need to compare two reference types by their values. I can explicitly call Equals() or I can overload operator== to perform the desired comparison.
However, overloading operator== for value comparison kinda-sorta violates the principle of least astonishment. On the other hand explicitly calling two-object Equals looks like overkill.
What is standard practice here?
I know how to override Equals(). The question was whether it is commonly acceptable to override operator== to test for value equality on reference types or whether it is commonly accepted practice to explicitly call Equals/ReferenceEquals to explicitly specify which comparison you want.
What is standard practice?
The "standard practice" is, if you want to check two elements for equality which isn't reference equality, you need to implement IEquatable<T>, which introduces a Equals(T other) method, and override GetHashCode. That way, you control the way these two objects are compared. Usually, this includes overriding the == and != operators as well.
while for value types it performs (AFAIK) equivalent of Equals() using
reflection.
Only if your value type has a member which is a reference type. If it's all value types, it will do a bit comparison of these two objects:
// if there are no GC references in this object we can avoid reflection
// and do a fast memcmp
if (CanCompareBits(this))
return FastEqualsCheck(thisObj, obj);
The question was whether it is commonly acceptable to override
operator== to test for value equality on reference types
It really depends on what you're doing. It is encouraged to override the == operator once you override Equals because you want a consistent behavior value equality semantics. This depends on your definition of equality between two objects.
Although, If an object is mutable, then doing value comparison might result in odd scenarios where two objects are considered equal but later, one is mutated. This should definitely be analyzed on per case basis. Usually, overriding Equals should suffice.
Equals() performs value comparison of two objects.
This is not true. The default behavior of object.Equals on value types is to compare each of the fields using their definition of equality, the default behavior of reference types is to compare their references. It can be overridden to do whatever you want it to do. It is exactly the same as the == operator in this regard.
The only difference between the == operator and Equals is that Equals will perform a virtual dispatch on the first (but not the second) operand, finding the implementation of the method based on the runtime type of that object. The == operator is entirely statically bound; it considers only the compile time type of both operands. Other than this difference in binding both have the same default behaviors, and both can be overridden to provide whatever implementation you want.
The standard practice is to always ensure that the behavior of Equals and operator == is the same for your type. If you override the Equals method to change the equality semantics, then you should also overload the == operator to provide *identical semantics`, and vice versa.
The question was whether it is commonly acceptable to override
operator== to test for value equality
It depends on the object, if the object is immutable then you can override == operator, otherwise not. (Remember they are just guidelines).
See: Guidelines for Overriding Equals() and Operator == (C# Programming Guide)
By default, the operator == tests for reference equality by
determining whether two references indicate the same object.
Therefore, reference types do not have to implement operator == in
order to gain this functionality. When a type is immutable, that
is, the data that is contained in the instance cannot be changed,
overloading operator == to compare value equality instead of reference equality can be useful because, as immutable objects, they
can be considered the same as long as they have the same value. It
is not a good idea to override operator == in non-immutable types.
It's a good practice to give a semantic meaning to your code. So, if reference comparison is really something you should care about, use default behaviour for your classes; otherwise your application context dependent logic should be used for comparison. (with consistent behaviour of all the equality members like Equals, GetHashCode and operators)
Link:
• Consider overriding Equals on a reference type if the semantics of
the type are based on the fact that the type represents some value(s).
• Most reference types must not overload the equality operator, even
if they override Equals. However, if you are implementing a reference
type that is intended to have value semantics, such as a complex
number type, you must override the equality operator.
a) To my understanding, for different instances of a reference type to be interchangeable, we should override both Equals method and the equality operator and also make the type immutable?
b) Doesn't a reference type having value semantics suggest that different instances ( that represent the same value ) of that type should be interchangeable?
c) But according to above quote, certain reference types with value semantics should only have Equals method overridden, but not also the equality operator. How can we claim such types have value semantics, since instances of that type are obviously not interchangeable?
d) So based on what criteria do we decide whether a reference type with value semantics should only have its Equals method overridden or also its equality operator? Simply based on whether or not we're willing to make the type immutable?
thanx
Regarding point A, yes, the type ought to be immutable. From MSDN:
You should not override Equals on a mutable reference type.
I think that D is the core question here, and the framework design guidelines seem to indicate that this comes down to performance:
AVOID overloading equality operators on reference types if the
implementation would be significantly slower than that of reference
equality.
Eric Lippert has some interesting things to say about this here. My favorite quote from it is:
The long answer is that the whole thing is weird and neither works the
way it ideally ought to.
Personally this lets me breathe a sigh of relief, as I have always been of the opinion that "==" is functionally a readable shorthand for Equals() (even though I know it isn't).
according to msdn
IStructuralEquatable
Defines methods to support the comparison of objects for structural
equality. Structural equality means that two objects are equal because
they have equal values. It differs from reference equality, which
indicates that two object references are equal because they reference
the same physical object.
isnt it what Equals should do ? ( when overriding IEquatable) ?
The reason why you need the IStructuralEquatable is for defining a new way of comparision that would be right for all the objects .
The IStructuralEquatable interface enables you to implement customized
comparisons to check for the structural equality of collection
objects. That is, you can create your own definition of structural
equality and specify that this definition be used with a collection
type that accepts the IStructuralEquatable interface.
For example if you want a list that will sort all its elements by a specific definition.
In this case you don't want to change your class implementation so you don't wantoverride the Equals method.
this will define a general way to compare objects in your application.
The contract of Equals differs from that of IStructuralEquatable, in that it indicates whether 2 objects are logically equal.
By default, Equals on a reference type indicates whether two object references reference the same object instance. However, you are able to override Equals according to the logic of your application.
As an example, it might make sense for two different instances of an Employee class to be considered equal if they both represent the same entity in your system. To achieve this, employee objects with matching SSN properties would be treated as logically equal, even if they were not structurally equal.
List<tinyClass> ids = new List<tinyClass();
ids.Add(new tinyClass(1, 2));
bool b = ids.IndexOf(new tinyClass(1, 2)) >= 0; //true or false?
If it compares by value, it should return true; if by reference, it will return false.
If it compares by reference, and I make tinyClass a struct - will that make a difference?
From MSDN:
This method determines equality using the default equality comparer EqualityComparer<T>.Default for T, the type of values in the list.
The Default property checks whether type T implements the System.IEquatable<T> generic interface and if so returns an EqualityComparer<T> that uses that implementation. Otherwise it returns an EqualityComparer<T> that uses the overrides of Object.Equals and Object.GetHashCode provided by T.
It seems like it uses the Equals method, unless the stored class implements the IEquatable<T> interface.
For a class, with the default implementation of Equals - it will compare by reference.
If you change it to a tinyStruct, it will compare it by value.
It depends on the object's implementation of .Equals(..). By default for an object, the references are compared. If you did change it to a struct, then I believe it would evaluate to true based on the equality of the private members, but it would still be more programmically sound to implement IEquatable.
Be sure to implement .Equals(..) for your struct, as the default implementation may use reflection to compare each field, which is very expensive.
Read more at: http://blogs.microsoft.co.il/blogs/sasha/archive/2007/08.aspx
It also may be related to which of the class or struct instance is kept in the list, because of structs' equal implementation is based on values' equality.