I haven't used this before, but figured I'd take a look at the documentation and code anyway.
The comment on the ObjectId property states the criteria for determining whether two ParseObject instances are considered equal:
The combination of a Parse.ParseObject.ClassName and an Parse.ParseObject.ObjectId uniquely identifies an object in your application.
So if the ClassName and ObjectId properties are equal, the two instances are equal:
var my1 = MyParseObject.Get<ParseObject>("MyRelation");
var my2 = MyOtherParseObject.Get<ParseObject>("MyRelation");
return my1.ObjectId == my2.ObjectId && my1.ClassName == my2.ClassName;
But instead of having to do that manually, you found the method they provided that does it for you:
return MyParseObject.Get<ParseObject>("MyRelation")
.HasSameId(MyOtherParseObject.Get<ParseObject>("MyRelation"));
From the HasSameId documentation:
A helper function for checking whether two ParseObjects point to the same object in the cloud.
Here's what it's doing internally (there's other stuff too, but this is the comparison part):
return other != null
&& object.Equals((object) this.ClassName, (object) other.ClassName)
&& object.Equals((object) this.ObjectId, (object) other.ObjectId);
A note about your original code that was using the == sign...
If the ParseObject class had overloaded the == operator and specified that it should compare the ClassName and ObjectId, then your original code would have worked.
Since they didn't overload that operator, and the default behavior of the == operator is to do a reference comparison, and MyParseObject.Get<ParseObject> and MyOtherParseObject.Get<ParseObject> are technically two different objects, it returned false.