In the case of strings, you are probably not going to use reference equality. To access equality and inequality in common methods, it is best to:
EqualityComparer<T>.Default.Equals(x,y); // for equality Comparer<T>.Default.Compare(x,y); // for inequality
i.e.
static bool AreValuesEqual<T>(T first, T second) where T : class { return EqualityComparer<T>.Default.Equals(first,second); }
It still uses overloaded Equals , but also processes zeros, etc. For inequality, this processes zeros for both IComparable<T> and IComparable .
For other operators, see MiscUtil .
Take the question; when:
string intro1 = "My name is Jon"; string intro2 = "My name is Jon"; Console.WriteLine(intro1 == intro2); Console.WriteLine(AreReferencesEqual(intro1, intro2));
You get true , true because the compiler and runtime are designed to work with strings; any literals you use are interned, and the same instance is used every time in your AppDomain. the compiler (and not the runtime) also concat if possible - i.e.
string intro1 = "My name is " + "Jon"; string intro2 = "My name is " + "Jon"; Console.WriteLine(intro1 == intro2); Console.WriteLine(AreReferencesEqual(intro1, intro2));
is the exact same code as in the previous example. There is no difference. However, if you force it to concatenate strings at run time, it is assumed that they are likely to be short-lived, so they are not interned / reused. So, in the case of:
string name = "Jon"; string intro1 = "My name is " + name; string intro2 = "My name is " + name; Console.WriteLine(intro1 == intro2); Console.WriteLine(AreReferencesEqual(intro1, intro2));
you have 4 lines; “John” (interned), “My Name” (interned), and two different copies from “My Name is John”. Therefore, == returns true, and referential equality returns false. But value-equality ( EqualityComparer<T>.Default ) will still return true.