Why does Contains compare objects differently than ==? - c#

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.

Related

How Does FirstOrDefault Test for Equality?

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.

Why do string datatypes always perform value comparison

I was looking for the difference between == and .Equals methods in C# and I found that the first one compares the object references, and the second one compares the objects values, except for the string datatypes both == and .Equals() does a content comparison. I can't really find an explanation for that, is it because the string datatypes are immutable ?
Here's what I want to say
object obj1 = "Test";
object obj2 = new string("Test".ToCharArray());
Console.WriteLine(obj1.Equals(obj2) + " " + (obj1 == obj2));
string a = "Test";
string b = "Test";
Console.WriteLine(a.Equals(b) + " "+ (a == b));
Output
True False
True True
In fact for the first comparison we have two different objects with same value and we got as result True and false, but for the case of string we have true for both comparison
This isn't true at all. == is an overridable operator, and Equals is an overridable method. It's up to the class to define how each of them behaves.
Perhaps you're confusing C# with Java?
If you want to do a reference comparison, use object.ReferenceEquals. Everything else is implementation dependant (though note that operator overrides are checked statically, so e.g. (object)someString == (object)someOtherString will do a reference comparison, not a value comparison; Equals doesn't have this "problem").
Most often, both == and Equals are designed to give the same answer (though == is always stricter about types in the comparison, as mentioned before). This applies double for structs, where a reference comparison doesn't really make much of a sense anyway.
And of course, the compiler doesn't actually do any checks. If I want, I can override the == operator to always return false. Or to only check some ID for equality. Or to change the objects being compared, if you are feeling particularly evil. In the end, it's just a static method like any other (with a few restrictions).
EDIT:
To address your edit directly, string always performs a content comparison because both its == and Equals are overriden to perform a content comparison. However, that doesn't mean that it always performs a costly char-by-char comparison - if you look how string.Equals is actually implemented, you can see that it tries a few things to avoid the costly comparison:
If the string is null, they must be different
If the two strings are reference-equal, they must also be content-equal
If the two strings don't have the same length, they must be different
You can see the actual by-value comparison method here - http://referencesource.microsoft.com/#mscorlib/system/string.cs,11648d2d83718c5e A simple piece of unsafe code, but manually written code nevertheless. There's no automatic value comparison in .NET (though there's tricks that come close).
It's because it makes sense.
Java couldn't do it this way because it doesn't have operator overloading, but that's no argument in C#.
This isn't unique to strings, by the way. Any type could overload the == operator to do something similar.
Any object can override/overload Equals or ==, so they can behave however the library author wants them to behave.

C# System.Object.operator==()

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.

C# == is different in value types and reference types?

In Java there are "==" and "equals" operator for reference types and "==" for value types. for reference type, "==" means both objects point to the same location and "equals" means their values are the same. does C# has similar operators for value type and reference types?
Well, == can be overloaded for reference types. For example:
string a = new string('x', 10);
string b = new string('x', 10);
Console.WriteLine(a == b); // True
Console.WriteLine(Object.ReferenceEquals(a, b)); // False
Unless it's overloaded, == means "reference equality" aka "object identity" for reference types. (As Marc says, you may override Equals without overloading ==.)
For value types, you have to overload == otherwise the C# compiler won't let you use it for comparisons. .NET itself will provide an implementation of Equals which usually does the right thing, but sometimes slowly - in most cases, if you write your own custom value type you'll want to implement IEquatable<T> and override Equals as well - and quite possibly overload various operators.
C# allows the == operator to be overloaded (and the Equals method to be overridden - although == and Equals don't have to mean the same thing).
If you want to mean "the same instance", then object.ReferenceEquals (for reference-types) is the best option. Value types default to internal equality.
Straight out of MSDN:
For predefined value types, the
equality operator (==) returns true if
the values of its operands are equal,
false otherwise. For reference types
other than string, == returns true if
its two operands refer to the same
object. For the string type, ==
compares the values of the strings.
Jon Skeet should be able to give you a perfect answer though :P
When should I use == and when should I use Equals?
http://blogs.msdn.com/csharpfaq/archive/2004/03/29/102224.aspx
This is precisely the way it works with .NET as well. The C# FAQ blog explains equals better:
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.

What is the difference between .Equals and == [duplicate]

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.

Categories