25
What is the difference in the use of the method Equals
for the operator ==
in situations of comparison between (1) value types and (2) reference types?
25
What is the difference in the use of the method Equals
for the operator ==
in situations of comparison between (1) value types and (2) reference types?
26
According to Microsoft in text written by Jon Skeet:
The method Equals
is only a virtual method defined in System.Object
, and may be superimposed by any classes that choose to do so. The ==
is an operator that can be overloaded by classes, when she usually has identity behavior.
For reference types, where ==
has not been overloaded, it compares if 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 types of values provided by . NET provide their own overhead. A standard implementation of Equals()
for a type of value is provided by ValueType
, and uses reflection to make the comparison, which makes it significantly slower than a specific implementation for the type would normally be. This implementation also calls Equals()
in pairs of references within the two values being compared.
However, the main difference between the two types of comparison under normal conditions of use (where it is unlikely that you define your own types of value) is polymorphism. Operators are overloaded, not overlapped (override), which means that unless the compiler knows to call the more specific version, it will only call the identity version. To illustrate this, here is an example:
using static System.Console;
public class Program {
public static void Main() {
// cria duas variáveis iguais mas distintas uma da outra
string a = new string(new char[] {'h', 'e', 'l', 'l', 'o'});
string b = new string(new char[] {'h', 'e', 'l', 'l', 'o'});
WriteLine (a == b);
WriteLine (a.Equals(b));
// o mesmo teste usando os mesmo dados mas como variáveis do tipo `Object`
object c = a;
object d = b;
WriteLine (c == d);
WriteLine (c.Equals(d));
}
}
The result is:
True
True
False
True
The third line is false because the compiler can only call the unburdened version of ==
since he does not know the content of c
and d
are the two references of strings. Since they are references to different strings, the identity operator returns false.
So when should you use the operator? The basic rule is that for almost all reference types, the use is equal to when you want to test equality instead of reference identity. The exception is to strings - compare strings with ==
makes things much simpler and more readable, but it is necessary to remember that both sides of the operator should be expressions of the type string, to get the comparison to work properly.
For value types, it is usually used ==
for better readability. It gets more complicated if a type of value, provides an overload to ==
which acts differently to Equals
, but this would be such a badly designed situation.
Summing it up:
You choose what each should do according to the intuitive expectation of the programmer.
What the programmer expects to compare when he uses one ==
? This is what this comparison should do, no matter how it is done. It can compare its members or references. It should compare identity.
Already the method Equals()
expects the comparison to be based on the value of the type. That is, based on their value, the members relevant to the type.
It is good to remember that there is a method ReferenceEquals()
which has the function of specifically comparing the references of objects.
It is common for the operator ==
choose to use the Equals()
or the implementation of ReferenceEquals()
.
The operator ==
is static and works more like an extension method.
There are cases where the Equals()
has three possible versions for choice of compiler:
object
(Equals(object, object)
);object
(Equals(object)
);IEquatable<short>
(Equals(short)
).So inconsistencies can occur.
int myInt = 1;
short myShort = 1;
object objInt1 = myInt;
object objInt2 = myInt;
object objShort = myShort;
WriteLine(myInt == myShort); // cenário 1 true
WriteLine(myShort == myInt); // cenário 2 true
WriteLine(myInt.Equals(myShort)); // cenário 3 true
WriteLine(myShort.Equals(myInt)); // cenário 4 false!
WriteLine(objInt1 == objInt1); // cenário 5 true
WriteLine(objInt1 == objShort); // cenário 6 false!!
WriteLine(objInt1 == objInt2); // cenário 7 false!!!
WriteLine(Equals(objInt1, objInt2)); // cenário 8 true
WriteLine(Equals(objInt1, objShort)); // cenário 9 false!?!
This is a type that exemplifies well as semantics is more important than the linearity of the functioning. See the examples:
string s1 = "abc";
string s2 = "abc";
WriteLine(object.ReferenceEquals(s1, s2)); //retorna true
This occurs because of a flame technique interning trying to repurpose an existing allocation of a string identical to the one you try to allocate again. But this is an exception. See now:
string s3 = "abc";
string s4t = "ab";
string s4 = s4t + "c";
WriteLine(object.ReferenceEquals(s3, s4)); //retorna false
WriteLine(s3 == s4); //retorna true
If the operator ==
to adopt the comparison of references as usual with types by reference the result would be strange. How the equality comparison of "abc" and "abc" can return false
? Can not, so the comparison is made on the identity, that in the case of type string is its value and not its reference.
Behold working in the ideone. And in the .NET Fiddle. Also put on the Github for future reference.
em texto escrito pelo Jon Skeet
+1!
15
Basically it works like this:
Boolean
(bool
), Byte
(byte
), SByte
(sbyte
), Int16
(short
), UInt16
, Int32
(int
), Uint32 (uint
), Int64
(long
), Uint64 (ulong
), IntPtr
, UIntPtr
, Char
(char
), Double
(double
), or Single
(single
)), the comparison between two variables shall be by value;System.Object.ReferenceEquals()
;==
for comparison between two objects, the method actually used will be the ReferenceEquals
.
structs
. where it is mandatory to burden the operator ==
in order to use it.In this case, what C# offers is the possibility to rewrite the method Equals
for a specific class, preferably to make the comparison rules more flexible.
Se for usado o operador == para comparação entre dois objetos, o método utilizado na verdade será o ReferenceEquals
When type is by reference. For structs it is mandatory to overload the ==
to be able to use it. BTW +1
True. I will supplement the reply. Thank you!
5
If by "primitive" types you mean those for which the Framework has synonyms, such as System.Int32
(int
), System.Boolean
(bool
), System.DateTime
(DateTime
) etc..
If they are structs, you need to overload the operator ==
to be able to use it. Already the method Equals
, For at least two instances of the same type, it will compare the values of the members of the struct, and return true if there is a member-by-member match. Whether both operators will give the same result or not depends on their implementation of the ==
.
Already for reference types, the operator ==
, not being overloaded, will compare the references, not the values themselves. Thus, two equivalent objects (i.e.: an instance of some kind and a deep clone) can be "different" when compared to the ==
. Already the method Equals
, which can also be overburdened, makes member-to-member comparison for various native types - but this is a matter of implementation of each type, not a gross comparison like that of structs.
-1
If Voce has a null object, Equals will not work. For example:
String nome = null
if (nome.equals("Nome"){
//Faça alguma coisa
}
This code will return a Nullpointerexception error because if name is null it is not possible to access the equals method. For primitive types, it is recommended to use the ==.
EDIT: Sorry, I answered as if it were in Java. I believe that maybe it applies to C#
Caso voce tenha um objeto do tipo nulo
Null is not a type. And the code will give error because you are calling a method from a null reference. The same goes for Java, only changes the exception name. If nome
had a value, you could pass null to the Equals method (which is with capital 'E').
Browser other questions tagged c# .net oop operators method
You are not signed in. Login or sign up in order to post.
Just a hint, in C# there is no concept of primitive types. There are types by value (
struct
andenum
) and types by reference (class
,interface
,delegate
, etc.). See more on http://answall.com/questions/14490/alocacao-de-memoria-em-c-tipos-valor-e-typos-referenced/14492#14492– Maniero