I have a reference type that implements the IEquatable Interface. I have a Hashset that contains a single object. I then create an object that, by IEquatable's standards are example the same. But, when I run
var equivalentEntry = _riskControlATMEntries[grouping.Key].FirstOrDefault(e => e == atmEntry);
on the object I get null.
On the otherhand when I do
var equivalentEntry = _riskControlATMEntries[grouping.Key].FirstOrDefault(e => e.Equals(atmEntry));
I get the object that is considered equal based on the IEquatable interface's implementation.
So why does a HashSet rely on public bool Equals(ReferenceType other) but FirstOrDefault does not? What equality is the == operator in FirstOrDefault(e => e == other) looking for?
FirstOrDefault doesn't compare items for equality at all. You provided a filtering delegate that uses the == operator to compare the two objects in one case and used the Equals method in the other.
The == operator does whatever the class defines it to do by that type, or if not defined, by the closest base type that does (with object being the base type that is always there, and will always have a definition if nothing better was defined; it will compare objects based on their reference). Good design says that you should make sure the == operator for a class is defined to behave exactly the same as the Equals method, but nothing in the language forces you to do this, and apparently this class doesn't ensure they're the same, and it's unsurprisingly causing you problems.
Related
Given an instance of an object in C#, how can I determine if that object has value semantics? In other words, I want to guarantee that an object used in my API is suitable to be used as a dictionary key. I was thinking about something like this:
var type = instance.GetType();
var d1 = FormatterServices.GetUninitializedObject(type);
var d2 = FormatterServices.GetUninitializedObject(type);
Assert.AreEqual(d1.GetHashCode(), d2.GetHashCode());
What do you think of that approach?
You can test for implementation of Equals() and GetHashCode() with this:
s.GetType().GetMethod("GetHashCode").DeclaringType == s.GetType()
or rather per #hvd's suggestion:
s.GetType().GetMethod("GetHashCode").DeclaringType != typeof(object)
Some some object s, if GetHashCode() is not implemented by it's type, this will be false, otherwise true.
One thing to be careful on is that this will not protect against a poor implementation of Equals() or GetHashCode() - this would evaluate to true even if the implementation was public override int GetHashCode() { }.
Given the drawbacks, I would tend towards documenting your types ("this type should / should not be used for a dictionary key..."), because this isn't something you could ultimately depend upon. If the implementation of Equals() or GetHashCode() was flawed instead of missing, it would pass this test but still have a run-time error.
FormatterServices.GetUninitializedObject can put the object in an invalid state; It breaks the guaranteed assignment of readonly fields etc. Any code which assumes that fields will not be null will break. I wouldn't use that.
You can check whether GetHashCode and Equals is overridden via reflection, but that's not enough. You could override the method call base class method. That doesn't count as value semantics.
Btw value semantics doesn't mean equal hashcodes. It could be a collision too; Value semantics means that two objects with equals properties should return same hashcode as well as equals method should evaluate to true.
I suggest you to create an instance, assign some properties, clone it; Now both hashcodes should be equal and calling object.Equals(original, clone) should evaluate to true.
You can see if an object defines its own Equals and GetHashCode using the DeclaringType property on the corresponding MethodInfo:
bool definesEquality = type.GetMethod("Equals", new[] { typeof(object) }).DelcaringType == type && type.GetMethod("GetHashCode", Type.EmptyTypes).DeclaringType == type;
In my program, I have objects derived from Dictionary. I need to check if 2 objects are equal, so I made an overload operator ==.
But at a later point, I need to check if a object is null.
If (object == null)
{...}
So at this point, the program goes into the overload operation I have defined, but will throw a NullReferenceException, since one of the objects to compare is null.
So within the overload operation, I need to check if one object is null, but without using ==, since that would give me a StackOverflowException.
How can I check this?
In my program, I have objects derived from Dictionary.
I would strongly reconsider deriving from Dictionary in the first place. That's very rarely a good idea. Favour composition over inheritance in general, and think very carefully about how you want equality (and hash codes) to behave in the face of mutable data. It's usually a bad sign if two objects are equal at one point and then not equal later.
So at this point, the program goes into the overload operation I have defined, but will throw a NullReferenceException, since one of the objects to compare is null.
That's the problem. Your overloaded == operator should not throw an exception - it should compare the value with null.
Typically an overload of == looks something like this:
public static bool ==(Foo left, Foo right)
{
if (ReferenceEquals(left, right))
{
return true;
}
if (ReferenceEquals(left, null))
{
return false;
}
// Equals should be overridden, and should be handling the case where
// right is null (by checking with ReferenceEquals too). Also consider
// implementing IEquatable<Foo>
return left.Equals(right);
}
Here Object.ReferenceEquals is used to perform the reference identity comparison. You could use this outside (in the code that you're currently considering changing) but it would be cleaner just to make == behave correctly.
You either need to cast to object,
(object)obj == null
or use object.ReferenceEquals(obj, null);
(object is not a nice name for an object)
You have to check for null in your implementation of overriden ==, following these guidelines for example :
http://msdn.microsoft.com/en-us/library/ms173147%28v=vs.80%29.aspx
You could also use
object.ReferenceEquals(myInstance, null);
Please note that overriding base operators such as == and/or directly overriding .Net base types such as Dictionary are both not very good practices.
overriding the == operator, as you have discovered, has non-obvious side effects and generally should be avoided.
You might consider having your object implement IComparable instead, and then calling CompareTo instead of ==.
use the is null operator from c# 7
if(object is null)...
Object t = 4;
Object s = 4;
if (t == s) { // false
}
List<Object> q = new List<object>() { t };
Boolean found = q.Contains(s); // found = true!
In the above code, I am not surprised by t == s returning false; it's comparing references to two objects and the references aren't the same.
But I am surprised the the Contains is returning true; obviously it's not just comparing object references..it's like it's comparing the unboxed values of 4 and 4..but how and why does it know to unbox the objects to compare them? I'm trying to understand the bigger pricniple at play here.
The expression
q.Contains(s)
is looking for an element of q for which EqualityComparer<object>.Default.Equals(element, s) is true. For boxed primitives, this compares the values.
Contains, internally, is using the instance object.Equals method to compare the elements. It is not using the == operator.
The Equals method is virtual, whereas the == operator is static. This means that the == operator will determine which code to run based on the compile time type of the variable (and not the object at run time that the variable holds). A virtual method, on the other hand, is not statically bound. It determines which overload of Equals to run based on the run time type of the value the variable.
According to the Contains documentation:
Determines whether a sequence contains a specified element by using
the default equality comparer.
Contains uses Equals methods instead of == operator.
== uses the type of the variables to determine what equality to compare.
For object/object it will do a reference equality.
Contains will use the Equals method which is virtual and may be overloaded to do a value compare. In this case int is written as such.
Contains uses object.Equals(object), which for ints are implemented so that 4.equals(4) is true. == with objects on each side uses reference comparison only.
Also of note: object.Equals(t, s) == true because this method uses the instance's Equals method if reference equality fails.
I'm tryign to get my head around the use of System.Object.operator==().
My Effective C# book, and the page here (http://www.srtsolutions.com/just-what-is-the-default-equals-behavior-in-c-how-does-it-relate-to-gethashcode), says that:
"System.Object.operator==() will call a.Equals(b) to determine if a and b are equal".
So with my code:
object a = 1;
object b = 1;
if(object.Equals(a, b))
{
// Will get here because it calls Int32.Equals(). I understand this.
}
if(a == b)
{
// I expected it to get here, but it doesn't.
}
I expected (a == b) to call Int32's overriden Equals and compare values in the same way that static objet.Equals() does. What am I missing?
Edit: I should perhaps have added that I can see what (a == b) is testing - it's testing reference equality. I was thrown by the book which seems to suggest it will work internally much as static object.Equals(obect, object) will.
I'm not sure why the book would say that; it is emphatically untrue that the default == calls Equals. Additionally, object does NOT overload ==. The operator == by default performs a value-equality comparison for value types and a reference-equality comparison for reference types. Again, it is NOT overloaded for object (it is for string). Therefore, when you compare object a = 1 and object b = 1 using the == operator you are doing a reference-equality comparison. As these are different instances of a boxed int, they will compare differently.
For all that are confused by this issue, I encourage you to read §7.10 and especially §7.10.6 of the specification extremely carefully.
For more on the subtleties of boxing (or why we need it in the first place), I refer you to a previous post on this subject.
As the object type doesn't override == and == checks for reference equality by default, the references of a and b are compared, as both are objects. If you want to compare value equality, you have to unbox the ints first.
When two objects are tested for equality they are tested to see if they are referencing the same object. (EDIT: this is generally true, however == could be overloaded to provide the functionality that you receive from a.equals)
So
object a = 1;
object b = 1;
These do not point to the same address space.
However if you did
object a = 1;
object b = a;
Then these would point to the same address.
For a real life example, take two different apartments in the same building, they have the exact same layout, same 1 bedroom, same kitchen, same paint everything about them is the same, except that apartment a is #101 and apartment b is #102. In one sense they are the same a.equals(b), but in another sense they are completely different a != b.
== implementation of object checks for identity, not equality. You have two variables that point to two different objects that's why == returns false.
You declared a and b as object which is a reference type and not a value type. So with a==b you are comparing references of objects (which will be different) rather than the values.
System.Object.operator==() will call a.Equals(b) to determine if a and b are equal
This is simply not true. If that were the case then you'd have a == b returning true, since a.Equals(b) returns true. Equals is a virtual method, so it doesn't matter that int values are boxed; if you call a.Equals, that compiles to a callvirt and the vtable is used.
So the static == operator does not use a.Equals(b) internally. It tests for reference equality by default. It only does otherwise if the static == operator has been overloaded for the types in the expression as they are declared at compile time.
System.Object does not overload ==, so a == b just tests for reference equality (and returns false). Since operator overloading is implemented as a static method, it's not virtual.
Object.Equals, on the other side, is specified as follows:
The default implementation of Equals supports reference equality for reference types, and bitwise equality for value types. Reference equality means the object references that are compared refer to the same object. Bitwise equality means the objects that are compared have the same binary representation.
Since a and b have the same binary representation, Object.Equals(a, b) returns true.
This question already has answers here:
C# difference between == and Equals()
(20 answers)
Closed 9 years ago.
What is the difference between a.Equals(b) and a == b for value types, reference types, and strings? It would seem as though a == b works just fine for strings, but I'm trying to be sure to use good coding practices.
From When should I use Equals and when should I use ==:
The Equals method is just a virtual
one defined in System.Object, and
overridden by whichever classes choose
to do so. The == operator is an
operator which can be overloaded by
classes, but which usually has
identity behaviour.
For reference types where == has not
been overloaded, it compares whether
two references refer to the same
object - which is exactly what the
implementation of Equals does in
System.Object.
Value types do not provide an overload
for == by default. However, most of
the value types provided by the
framework provide their own overload.
The default implementation of Equals
for a value type is provided by
ValueType, and uses reflection to make
the comparison, which makes it
significantly slower than a
type-specific implementation normally
would be. This implementation also
calls Equals on pairs of references
within the two values being compared.
using System;
public class Test
{
static void Main()
{
// Create two equal but distinct strings
string a = new string(new char[] {'h', 'e', 'l', 'l', 'o'});
string b = new string(new char[] {'h', 'e', 'l', 'l', 'o'});
Console.WriteLine (a==b);
Console.WriteLine (a.Equals(b));
// Now let's see what happens with the same tests but
// with variables of type object
object c = a;
object d = b;
Console.WriteLine (c==d);
Console.WriteLine (c.Equals(d));
}
}
The result of this short sample program is
True
True
False
True
Here is a great blog post about WHY the implementations are different.
Essentially == is going to be bound at compile time using the types of the variables and .Equals is going to be dynamically bound at runtime.
In the most shorthand answer:
== opertator is to check identity. (i.e: a==b are these two are the same object?)
.Equals() is to check value. (i.e: a.Equals(b) are both holding identical values?)
With one exception:
For string and predefined value types (such as int, float etc..),
the operator == will answer for value and not identity. (same as using .Equals())
One significant difference between them is that == is a static binary operator that works on two instances of a type whereas Equals is an instance method. The reason this matters is that you can do this:
Foo foo = new Foo()
Foo foo2 = null;
foo2 == foo;
But you cannot do this without throwing a NullReferenceException:
Foo foo = new Foo()
Foo foo2 = null;
foo2.Equals(foo);
At a simple level, the difference is which method is called. The == method will attempt ot bind to operator== if defined for the types in question. If no == is found for value types it will do a value comparison and for reference types it will do a reference comparison. A .Equals call will do a virtual dispatch on the .Equals method.
As to what the particular methods do, it's all in the code. Users can define / override these methods and do anything they please. Ideally this methods should be equivalent (sorry for the pun) and have the same output but it is not always the case.
One simple way to help remember the difference is that a.Equals(b) is more analogous to
a == (object)b.
The .Equals() method is not generic and accepts an argument of type "object", and so when comparing to the == operator you have to think about it as if the right-hand operand were cast to object first.
One implication is that a.Equals(b) will nearly always return some value for a and b, regardless of type (the normal way to overload is to just return false if b is an unkown type). a == b will just throw an exception if there's no comparison available for those types.
"==" is an operator that can be overloaded to perform different things based on the types being compared.
The default operation performed by "==" is a.Equals(b);
Here's how you could overload this operator for string types:
public static bool operator == (string str1, string str2)
{
return (str1.Length == str2.Length;)
}
Note that this is different than str1.Equals(str2);
Derived classes can also override and redefine Equals().
As far as "best practices" go, it depends on your intent.
For strings you want to be careful of culture specific comparisons. The classic example is the german double S, that looks a bit like a b. This should match with "ss" but doesn't in a simple == comparison.
For string comparisons that are culture sensitive use: String.Compare(expected, value, StringComparison....) == 0 ? with the StringComparison overload you need.
By default, both == and .Equals() are equivalent apart from the possibility of calling .Equals() on a null instance (which would give you a NullReferenceException). You can, however, override the functionality of either of them independently (though I'm not sure that would ever be a good idea unless you're trying to work around the shortcomings of another system), which would mean you could MAKE them different.
You'll find people on both sides of the aisle as to the one to use. I prefer the operator rather than the function.
If you're talking about strings, though, it's likely a better idea to use string.Compare() instead of either one of those options.