16

Possible Duplicate:
Difference between == operator and Equals() method in C#?

Two forms of equality, the first fails, the second succeeds.

(object)"abc" == (object)"abc"
false

((object)"abc").Equals((object)"abc")
true

In the below reference, we see "Equality operators in C# are not polymorphic"

ref: String Equality operator == in c#

btw: still not sure why this is an issue. I thought it might be something like this, but it isn't because this test succeeds.

    static void Main(string[] args) {
        var o = new classOfT<string>() { val = "abc" };
        Console.WriteLine((object)o.val == "abc");
    }

    public class classOfT<T> {
        public string val { get; set; }
    }

BTW: I DO NOT AGREE WITH THE EXACT DUPLICATE RULING ON THIS QUESTION, BUT HEY.

The Answer states:

... The String class contains both a static bool Equals(string a, string b) method and a static bool Equals(object a, object b) method. The difference is that the former is defined within the String class itself, whilst the latter is inherited from the Object class (which is the base class of String)

Semantically this makes sense, but does it make sense in the wider context of OO and the C# language?

Why am I bothering with the question? Well, just found a bug, and I'd like to file this in my brain under a rhyme or reason rather than under the "just remember this", it's bitten you before category.

Update:

currently thinking about this in terms of working with primitives (from a functional perspective) Vs polymorphism. Since I've been doing more and more functional stuff, this is probably why the mother tongue confused me. I'm not done thinking about this yet (no I'm not being pragmatic. I am drawn to language design). Thanks for responding all!

Community
  • 1
  • 1
sgtz
  • 8,849
  • 9
  • 51
  • 91
  • 1
    I'm not a C# guru, but it seems the first line is comparing the objects, which are distinct in memory, that's why it fails - and the second line is comparing the actual value 'abc' which is equal, and that's why it True. – Burhan Khalid Oct 08 '12 at 04:25
  • @BurhanKhalid You are correct. The equals method of string objects will compare string values stored inside the object. Whereas two different object references will never be equal. – rizalp1 Oct 08 '12 at 04:27
  • 1
    Interestingly, in LINQPad `(object)"abc" == (object)"abc"` returns `True` – Andrew Cooper Oct 08 '12 at 04:28
  • 1
    `(object)"abc" == (object)"abc"` return `true`. Just for a thought, what is your current culture ? – Habib Oct 08 '12 at 04:38
  • Both returned `true` for me in a new test project. – Kenneth K. Oct 08 '12 at 04:44
  • @Habib: CurrentCulture is en-GB. What is the culture you are using? – sgtz Oct 08 '12 at 04:50
  • @sgtz, mine is `en-US`, but for your culture it is also return true – Habib Oct 08 '12 at 04:57
  • 1
    @Habib: I will investigate further. The .net version is 4. Glad (and perplexed) that it is intuitively working as expected elsewhere. Thanks for letting me know. – sgtz Oct 08 '12 at 05:14
  • @Habib: started off a brand new project, and it works as expected there. Most strange. – sgtz Oct 08 '12 at 05:17
  • @sgtz: Please provide a *short but complete* example demonstrating the problem. The statements in your question are incorrect - making it hard to answer, as we don't know what you're really asking. – Jon Skeet Oct 13 '12 at 07:11
  • @JonSkeet: the behaviour was observed. I suspect (not proven yet) that generics lead to the problem. I accept that some of the statements I have made are incorrect. I just haven't found the root cause yet. A new example is coming. Thanks to all who helped me with a much needed sanity check. – sgtz Oct 13 '12 at 08:04
  • @sgtz: I doubt that the *exact* behaviour you've claimed was observed. I suspect it was something *similar*, but you've forgotten the difference, which turns out to be important. – Jon Skeet Oct 13 '12 at 08:06
  • @JonSkeet: you are normally scientific about these things aren't you? There you go, even Jon can doubt. – sgtz Oct 13 '12 at 08:08
  • @sgtz: I'm being scientific - an observation has to be repeatable to be useful. I don't believe you actually observed what you think you observed, and if you can't produce a program which lets *us* reproduce it, I'll believe your observations were incorrect. Isn't that the way science normally works? If you *can* produce a program which lets us observe the same effect, that will be great. – Jon Skeet Oct 13 '12 at 08:10
  • @JonSkeet: you used the word believe (hypothesis). An assertion is not a finding. In the scenario (which I'll get to explaining), the behaviour occurred every time (repeatable). My test case (above) was inside the context, so the observation was correct in that context. The mistake is that what I have presented doesn't let *you* get a repeatable result that agrees. We disagree, but we're both being scientific. ;-) – sgtz Oct 13 '12 at 08:38
  • @sgtz: I'm talking about "believing" because I don't have complete evidence either way. If someone said that they'd observed 1 + 1 giving 3 in C#, how would *you* react? I suspect you wouldn't believe them. Note that you haven't given us *any* indication of the context in which this unusual (and specification-violating) result was observed. That should have been in the question from the very start. Put it this way - if you regard your approach as being "scientific" you're not giving nearly enough information for peer review... – Jon Skeet Oct 13 '12 at 08:42
  • @JonSkeet: it's easy to turn up *now* with hindsight. Your faith in MS is stronger than mine. You obviously haven't been burned by COM before. Try not to be too emphatic. There's a process of discovery going on. In normal circumstances I'd agree that 1 + 1 is not equal to 3. – sgtz Oct 13 '12 at 08:45
  • @sgtz: Everything's relative - I've seen far more people on Stack Overflow misdiagnose issues (claim they've seen X when actually they've seen Y) than I have seeing the C# compiler and CLR violate the specifications. The latter has certainly occurred, but it's relatively rare. In the absence of *evidence* to the contrary, I tend to believe that the compiler will do the right thing. You haven't provided any decent evidence, hence my belief. (It's not clear what you mean about hindsight - I'm just going on your question. You decided how much information to present, after all.) – Jon Skeet Oct 13 '12 at 09:02
  • @JonSkeet: true. That and I could be presenting evidence rather than responding. I suspect that the compiler lost some meta along the way. Nothing major. For the minute, I'm relieved that my faith in the CLR has been restored. Re: I chose. Was trying to be succinct. What should the scope be: code fragment, entire program, program + OS, program + OS + hardware? I *thought* I was doing the right thing. – sgtz Oct 13 '12 at 09:44
  • @sgtz: Instead of just an expression, giving a complete console app we could run would have been the best approach. I suspect that in coming up with that, you'd have found out the difference. We still have no idea what context you were in, or how you were compiling/executing this. Basically, there has to be enough information for someone to reproduce. *Usually* OS and hardware aren't important for a .NET program, but if you've given enough information for people to run the code, they can *report* if it makes a difference. – Jon Skeet Oct 13 '12 at 09:48

4 Answers4

4
(object)"abc" 

will create an Object reference from the string object. So doing

(object)"abc" == (object)"abc"

will create two object references, which are not equal.

However, using the equals method will check to see if the value of the string stored is equal. Again, this is not the default implementation of all objects, but of the String object. For any custom object, you should define your own custom implementation of equals method to achieve this behavior.

rizalp1
  • 6,346
  • 2
  • 17
  • 19
  • 2
    You're not _creating_ two object references, you're just telling the compiler that you want to compare the two values as if they were each of type `object` which by default, compares references. – Jeff Mercado Oct 08 '12 at 04:35
  • 2
    You're not creating two objects at all - string literals are interned, so you're comparing two equal references. Only a reference comparison is used due to the casts to `object`, but as they're two references to the same object, the comparison will return true. – Jon Skeet Oct 13 '12 at 07:09
2

The code sample returns true.

(object)"abc" == (object)"abc"

I think you have provided different example than the code returning false in your application. CLR uses string interning for string optimization. Casting to System.Object will cause == operator to compare the references and due to string interning feature, the == operator will result in true. The comparison will only return false if parameters on both sides of the == operator will refer to different string objects on heap.

Check if the assembly has been marked with [assembly: CompilationRelaxations(System.Runtime.CompilerServices.CompilationRelaxations.NoStringInterning)] attribute or not.

jags
  • 2,022
  • 26
  • 34
  • In that particular case though, I don't think it's interning that allows that to be true, but the fact that they are both string literals with the same values which the compiler would then optimize to use the same string instance. – Jeff Mercado Oct 08 '12 at 05:20
  • @JeffMercado: Casting to System.Object and then using == operator is essentially the same thing as to use Object.ReferenceEquals method and the output will be true only if both sides of == operator reference to same instance of heap. The only compiler optimization I am aware of related to strings is string interning. There might be others but I am not aware of them. I think OP is having the problem in different code and has provided different example in the question. The OP may however verify that this is not the case of string interning. – jags Oct 08 '12 at 05:40
  • 1
    @jags, String constants are always the same object. See https://stackoverflow.com/a/4286639/892327, which references https://csharpindepth.com/Articles/Strings. – Nielsvh Nov 23 '19 at 00:44
1

String comparison should be done via String.Compare,

http://blogs.msdn.com/b/abhinaba/archive/2005/10/28/486173.aspx

http://msdn.microsoft.com/en-US/vstudio/aa496123?pull=/library/en-us/dndotnet/html/StringsinNET20.asp

I don't think you "found a bug", as Microsoft did the same many times in .NET BCL and it becomes common which we as developers have to adapt to. A simple example is that,

var ip1 = IPAddress.Parse("127.0.0.1");
var ip2 = IPAddress.Parse("127.0.0.1");

You will find ip1 != ip2, but ip1.Equals(ip2) == true. The recommended way to compare is IPAddress.Compare(ip1, ip2). Anyway, you have to remember something sometimes.

Lex Li
  • 60,503
  • 9
  • 116
  • 147
0

== operator:

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.

Equals:

Is overriden by the string class which will "return true if obj is a String and its value is the same as this instance; otherwise, false."

If your code is like below,

var s1= GetString1(); //some string object
var s2= GetString2(); //some string object containing same content as s1

(object)s1 == (object)s2
returns false - because == compares the references of the objects (which will be different if not interned)

((object)s1).Equals((object)s2)
returns true - because Equals will be called between actual strings at run time

But, in the current form, your code

(object)"abc" == (object)"abc"
((object)"abc").Equals((object)"abc")

should return true in both the cases because literal strings with same value get interned by default and hence refer to same object (i.e. references are also equal)

prashanth
  • 2,059
  • 12
  • 13