This code snippet is from C# in Depth
static bool AreReferencesEqual<T>(T first, T second)
where T : class
{
return first == second;
}
static void Main()
{
string name = "Jon";
string intro1 = "My name is " + name;
string intro2 = "My name is " + name;
Console.WriteLine(intro1 == intro2);
Console.WriteLine(AreReferencesEqual(intro1, intro2));
}
The output of the above code snippet is
True
False
When the main method is changed to
static void Main()
{
string intro1 = "My name is Jon";
string intro2 = "My name is Jon";
Console.WriteLine(intro1 == intro2);
Console.WriteLine(AreReferencesEqual(intro1, intro2));
}
The output of the above code snippet is
True
True
I cannot fathom why ?
EDIT: Once you understand string-interning following questions don't apply.
How are the parameters received at the Generic method AreReferencesEqual
in the second code snippet ?
What changes to the string type when it is concatenated to make the == operator not call the overloaded Equals method of the String type ?
A generic method can also be overloaded by nongeneric methods. When the compiler encounters a method call, it searches for the method declaration that best matches the method name and the argument types specified in the call—an error occurs if two or more overloaded methods both could be considered best ...
This means C++ has the ability to provide the operators with a special meaning for a data type, this ability is known as operator overloading. For example, we can overload an operator '+' in a class like String so that we can concatenate two strings by just using +.
Operator Overloading is the method by which we can change the function of some specific operators to do some different task. In the above syntax Return_Type is value type to be returned to another object, operator op is the function where the operator is a keyword and op is the operator to be overloaded.
A very popular and convenient example is the Addition (+) operator. Just think how the '+' operator operates on two numbers and the same operator operates on two strings. It performs “Addition” on numbers whereas it performs “Concatenation” on strings.
On the case of strings, you probably don't intend to use reference equality. To access equality and inequality in generic methods, your best bet it:
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);
}
This still uses the overloaded Equals
, but handles nulls etc too. For inequality, this handles nulls, and both IComparable<T>
and IComparable
.
For other operators, see MiscUtil.
Re the question; in the case of:
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 is designed to be efficient with strings; any literals that you use are "interned" and the same instance is used every time in your AppDomain. The compiler (rather than runtime) also does the 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 exactly the same code as the previous example. There is no difference at all. However, if you force it to concatenate strings at runtime, it assumes they are likely to be short-lived, so they are not interned/re-used. So in the case:
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 strings; "Jon" (interned), "My name is " (interned), and two different instances of "My name is Jon". Hence ==
returns true and reference equality returns false. But value-equality (EqualityComparer<T>.Default
) would still return true.
Learnt a new thing today.
I guess Jon said in one of the questions, I tried to answer.
When you build a string using concatenation, == will return true for 2 strings of matching value but they don't point to the same reference (which I thought, it should due to string interning. Jon pointed that string interning works for constant or literals).
In the generic version, it is calling object.ReferenceEquals (which is different than ==. In case of string, == does value comparison).
As a result, the concatenated version returns false whereas the constant (literal string) version returns true.
EDIT: I think Jon must be around to explain this in a much better way :)
Lazy me, I have bought the book but have yet to get started on it. :(
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With