As Jaroslav Jandek says (sorry I can't comment, not enough reputation)
Because it compares those two
instances, not their value (two
references).
And actually it's the same for tons of other cases! For ex
IPAddress ip1 = IPAddress.Parse("192.168.0.1");
IPAddress ip2 = IPAddress.Parse("192.168.0.1");
Both IP addresses represent the same address, but you have two distinct instances of the IPAddress class. So of course "ip1 == ip2" and "ip1.Equals(ip2)" are both false, because they don't point to the same object.
Now if you check "ip1.Address == ip2.Address" the result will be true as IPAddress.Address is a "long", so you're comparing 2 value types. Note that "ip1.ToString() == ip2.ToString()" will also be true even if a string is a reference type not a value type (but strings are really specials).
So indeed in your case you want to compare the FullName property (it's a string so no problem).
You say
Is it only by using the properties, i.e. the .FullName property that you are comparing value rather than instance?
Actually it has more to do with whether the property is a value type or a reference type. Also when comparing reference types, in most cases the comparison will be whether or not they point to the same object, but it's possible to override methods or create operators so that the comparison is done on the content of the objects (again just like Jaroslav Jandek already pointed out).
HTH