I have this code that checks the references of two variables, I came across this case which is a bit confusing :
string first = "10";
object second = 10.ToString();
dynamic third = second;
Console.WriteLine($"{first == second} {first == third}");
The result is : False True
My first question is why are the first and third references equal? If the third variable is equal to the second it should be False
because their object references aren't equal.
And I got confused when I changed the values to "1"
like below:
string first = "1";
object second = 1.ToString();
dynamic third = second;
Console.WriteLine($"{first == second} {first == third}");
Then the result becomes: True True
Why does this happen?
CodePudding user response:
I am not sure why it changes when you change it from 10 to 1
I believe it is an implementation detail and you should not rely on it (will try find something in the specs) but some positive single digit numbers are cached in int.ToString
implementation for .NET Core. Here is excerpt from UInt32ToDecStr
which is called internally by int.ToString
:
// For single-digit values that are very common, especially 0 and 1, just return cached strings.
if (bufferLength == 1)
{
return s_singleDigitStringCache[value];
}
As for equality - please check:
- C# difference between == and Equals().
- String interning in .Net Framework. (compiler will intern string literals, so all of them will point to the same address in memory)
- Using type dynamic
UPD:
Was not able to find anything in specs, but next code behaves differently in .NET Framework and .NET 6 (former one prints 11 times False
and the latter prints 10 times True
and one False
):
var dict = new Dictionary<int, string>()
{
{0, "0"},
{1, "1"},
{2, "2"},
{3, "3"},
{4, "4"},
{5, "5"},
{6, "6"},
{7, "7"},
{8, "8"},
{9, "9"},
{10, "10"},
};
foreach(var kvp in dict)
{
Console.WriteLine(object.ReferenceEquals(kvp.Key.ToString(), kvp.Value));
}
CodePudding user response:
The answer to the first question is because string equality isn't based on the object references as a reference type is by default.
first
and third
are both type string
, even if only known at runtime, so the System.String
's operator ==
override is called and:
...in turn, calls the static Equals(String, String) method, which performs an ordinal (case-sensitive and culture-insensitive) comparison.
As for the second question (edit) ...See @GuruStron's answer.
I'll also point out that Visual Studio 2022 provides a CS0253 compiler warning at first == second
:
Possible unintended reference comparison; to get a value comparison, cast the right hand side to type 'string'
CodePudding user response:
I am not sure why it changes when you change it from 10 to 1 but I think some part of your question is related to this information on Geeks for Geeks:
"In C# 4.0, a new type is introduced that is known as a dynamic type. It is used to avoid the compile-time type checking. The compiler does not check the type of the dynamic type variable at compile time, instead of this, the compiler gets the type at the run time. "