Generic Type parameters and Strings .. confused !


R

Ricardods1006

Could someone please clarify a small point of confusion for me please.

MSDN excerp ...

When applying the where T : class constraint, avoid the == and != operators
on the type parameter because these operators will test for reference
identity only, not for value equality. This is the case even if these
operators are overloaded in a type that is used as an argument. The following
code illustrates this point; the output is false even though the String class
overloads the == operator.

public static void OpTest<T>(T s, T t) where T : class
{
System.Console.WriteLine(s == t);
}
static void Main()
{
string s1 = "target";
System.Text.StringBuilder sb = new System.Text.StringBuilder("target");
string s2 = sb.ToString();
OpTest<string>(s1, s2);
}
.......................

Except if lines
System.Text.StringBuilder sb = new System.Text.StringBuilder("target");
string s2 = sb.ToString();
are changed to
string s2 = "target";

then the output is true.

I can't understand why this is, are these no longer two different objects if
I do not use StringBuilder

Many thanks
 
Ad

Advertisements

P

Peter Duniho

Ricardods1006 said:
[...] The following
code illustrates this point; the output is false even though the String class
overloads the == operator.

public static void OpTest<T>(T s, T t) where T : class
{
System.Console.WriteLine(s == t);
}
static void Main()
{
string s1 = "target";
System.Text.StringBuilder sb = new System.Text.StringBuilder("target");
string s2 = sb.ToString();
OpTest<string>(s1, s2);
}
.......................

Except if lines
System.Text.StringBuilder sb = new System.Text.StringBuilder("target");
string s2 = sb.ToString();
are changed to
string s2 = "target";

then the output is true.

I can't understand why this is, are these no longer two different objects if
I do not use StringBuilder

That is correct. It's a bit of a red herring to examine this in the
context of a generic method, as the issue exists more generally.

But the answer is, due to "string interning" (a variation of "string
pooling", which you may be familiar with from other languages), if you
use the string literal "target" multiple times, each time you use it it
will still refer to the same single object instance.

When you use StringBuilder to wrap the instance (and I'm sure this is in
fact why they use StringBuilder for that particular example), it copies
the contents of the string passed to it into the internal buffer of
StringBuffer, and when you retrieve that buffer as a String using the
ToString() method, you get a String instance that uses that buffer,
rather than the original interned string that was passed to the
StringBuilder constructor.

So, by wrapping the string in StringBuilder, you ensure a different
instance of String is created. Without doing that, the compiler and
run-time notice that the literals are identical and wind up using the
same object instance in each case.

Pete
 
Ad

Advertisements

R

Ricardods1006

Thank you very much

That is what I suspected but was not certain.

Peter Duniho said:
Ricardods1006 said:
[...] The following
code illustrates this point; the output is false even though the String class
overloads the == operator.

public static void OpTest<T>(T s, T t) where T : class
{
System.Console.WriteLine(s == t);
}
static void Main()
{
string s1 = "target";
System.Text.StringBuilder sb = new System.Text.StringBuilder("target");
string s2 = sb.ToString();
OpTest<string>(s1, s2);
}
.......................

Except if lines
System.Text.StringBuilder sb = new System.Text.StringBuilder("target");
string s2 = sb.ToString();
are changed to
string s2 = "target";

then the output is true.

I can't understand why this is, are these no longer two different objects if
I do not use StringBuilder

That is correct. It's a bit of a red herring to examine this in the
context of a generic method, as the issue exists more generally.

But the answer is, due to "string interning" (a variation of "string
pooling", which you may be familiar with from other languages), if you
use the string literal "target" multiple times, each time you use it it
will still refer to the same single object instance.

When you use StringBuilder to wrap the instance (and I'm sure this is in
fact why they use StringBuilder for that particular example), it copies
the contents of the string passed to it into the internal buffer of
StringBuffer, and when you retrieve that buffer as a String using the
ToString() method, you get a String instance that uses that buffer,
rather than the original interned string that was passed to the
StringBuilder constructor.

So, by wrapping the string in StringBuilder, you ensure a different
instance of String is created. Without doing that, the compiler and
run-time notice that the literals are identical and wind up using the
same object instance in each case.

Pete
.
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Top