If your type does not overload the Equals() method, you inherit one from the base Object type. The
documentation on this method states that, for reference types, it checks for
reference equality. This means that it checks whether two variables refer to the
same object (the same location in memory).
Looking at your first sample, your _emp1 and _emp2 variable both refer to the
same object. The assignment on the 2nd line did not create a copy, but assigned _emp2 to point to the object created for _emp1. Therefore, when you call the .Equals() method, it sees they are the same object and returns
true.
Looking at your second sample, your _emp1 and _emp2 variables refer to different objects. The second line of code creates a completely new object for _emp2 to refer to. When you call the .Equals() method, it sees that they are different objects and so returns
false.
You can choose to overload the default implementation of .Equals(), and instead look for
value equality. Value equality can equate two
different objects, if those objects can be said to have the same value. The most common way to do this is to also overload the GetHashCode() method, and simply compare the results of that method for each object inside your .Equals() implementation. In fact, while it's not very clearly documented that way, this is almost required for a class of any substance. It's very easy to make subtle mistakes when overloading this method, but the the current
documentation on the GetHashCode() function has a section titled "Notes to Implementors" that is very helpful in avoiding them.