Using ==
in this case resolves to System.Reference.Equals
.
.Equals
is a virtual method so the overridden version will be used, in this case it will be content comparison for string.
The first test compares a local variable to a literal (interned) string.
The second test compares the same interned string so both ==
and Equals
return true.
If you change your TestMethod1()
to this:
Assert.IsTrue(Foo<string>.Foo1(name, name));
it will pass because you are comparing the same object, so the reference equality returns true.
Edit: If we add this method:
public static bool Foo3(string item1, string item2)
{
return item1 == item2;
}
Then the following test will return true
:
Assert.IsTrue(Foo<string>.Foo3(name, "str1"));
because C# will resolve ==
in this case to the string value check.
This question is really a duplicate of this, with additional generic complexity.
Edit 2:
OK, time to dive into the MSIL. Foo1
looks like this:
.method public hidebysig static bool Foo1(!T item1,
!T item2) cil managed
{
// Code size 20 (0x14)
.maxstack 2
.locals init ([0] bool V_0)
IL_0000: nop
IL_0001: ldarg.0
IL_0002: box !T
IL_0007: ldarg.1
IL_0008: box !T
IL_000d: ceq
IL_000f: stloc.0
IL_0010: br.s IL_0012
IL_0012: ldloc.0
IL_0013: ret
} // end of method Foo`1::Foo1
You can see here it is using ceq
which is Push 1 (of type int32) if value1 equals value2, else push 0.
Here is Foo2
:
.method public hidebysig static bool Foo2(!T item1,
!T item2) cil managed
{
// Code size 23 (0x17)
.maxstack 2
.locals init ([0] bool V_0)
IL_0000: nop
IL_0001: ldarg.0
IL_0002: box !T
IL_0007: ldarg.1
IL_0008: box !T
IL_000d: callvirt instance bool [mscorlib]System.Object::Equals(object)
IL_0012: stloc.0
IL_0013: br.s IL_0015
IL_0015: ldloc.0
IL_0016: ret
} // end of method Foo`1::Foo2
This uses System.Object::Equals
- this is the virtual method and behaves as such, being overridden in the concrete type of the parameter - in this case string
.
Foo3
(which I added, which uses ==
on declared string
parameters) looks like this:
.method public hidebysig static bool Foo3(string item1,
string item2) cil managed
{
// Code size 13 (0xd)
.maxstack 2
.locals init ([0] bool V_0)
IL_0000: nop
IL_0001: ldarg.0
IL_0002: ldarg.1
IL_0003: call bool [mscorlib]System.String::op_Equality(string,
string)
IL_0008: stloc.0
IL_0009: br.s IL_000b
IL_000b: ldloc.0
IL_000c: ret
} // end of method Foo`1::Foo3
Here we observe explicit use of the System.String::op_Equality(string, string)
which is the string value check comparison.