Why is this passing Assert.AreSame()?
[TestMethod]
public void StringSameTest()
{
string a = "Hello";
string b = "Hello";
Assert.AreSame(a, b);
}
I understand ìt tests for reference equality, and is essentially the same as Assert.IsTrue(object.ReferenceEquals(a, b)) but it's clear that a and b are different string objects, regardless of them having the same values. If Ì set string b = a; I'd expect true, but that's not the case. Why isn't this test failing?
Thanks
The C# compiler will intern identical literal strings to the same const string reference.
So your code is equivalent to this:
private const String _hello = "Hello";
[TestMethod]
public void StringSameTest()
{
string a = _hello;
string b = _hello;
Assert.AreSame( a, b ); // true
}
To create a separate string instance that's identical to a const string use String.Copy():
string a = "Hello";
string b = a.Copy();
Assert.AreSame( a, b ); // false
However, do note that:
String.Copy() and String.Clone() are different!
Clone() does not actually clone the string value, it instead returns a reference to itself.
String.ToString() also returns a reference to itself.
String.Copy() is deprecated in .NET Framework and .NET Core and may be removed in a future version.
This is because there is no legitimate need to use String.Copy()
See Do string literals get optimised by the compiler?
Related
private class global
{
public static int a = 0;
public static int val = 0;
public static int c = -1;
public static string g = "";
}
private void button8_Click(object sender, EventArgs e)
{
global.a = global.a + 1;
global.c = global.c + 1;
string a = label2.Text;
if (string.ReferenceEquals(a, global.g))
{
MessageBox.Show("a");
//dataGridView1.Rows[global.c].Cells[1].Value = global.a;
//dataGridView1.Rows[global.c].Cells[2].Value = global.val * global.a;
}
else
{
dataGridView1.Rows.Add(label2.Text, global.a, global.val);
}
global.g = label2.Text;
}
If button8 is pressed again with label2.Text it should call MessageBox.Show() but somehow global.g = label2.text does not work. I tried with :
string a = "";
string b = "";
if (string.ReferenceEquals(a, b))
{
MessageBox.Show("a");
}
It works fine but then I change b to global.g it skips if...
As qqbenq states above... you should use String.Equals instead due to string interning.
You should NOT use reference equality to compare strings... as per Microsoft
you should not use ReferenceEquals to
determine string equality.
And a bit more detail further down in the link...
Constant strings within the same assembly are always interned by the
runtime. That is, only one instance of each unique literal string is
maintained. However, the runtime does not guarantee that strings
created at runtime are interned, nor does it guarantee that two equal
constant strings in different assemblies are interned.
Specifically to answer your question... how should I change my code...
Edited as #Servy mentioned to use the static string.equals for the case where a is null.
string a = "";
string b = "";
if (string.Equals(a, b))
{
MessageBox.Show("a");
}
You should pretty much always use Equals for comparing reference types. Only use ReferenceEquals if you really want to check if they are not only equal but actually point to the same reference.
The problem here is the use of ReferenceEquals instead of Equals.
ReferenceEquals will check for equality of the reference - which is to say, the pointer in memory to the underlying variable, not the value itself. this is a static method because it has such a precise use, it should never be overridden or hidden by a derived class.
Equals on the other hand will compare the objects themselves, and thus determine if their underlying values are the same. Since it's a string, you also have overloads of Equals which allow to specify exactly how the strings are being compared.
thus, change
if (string.ReferenceEquals(a, global.g))
{
MessageBox.Show("a");
//dataGridView1.Rows[global.c].Cells[1].Value = global.a;
//dataGridView1.Rows[global.c].Cells[2].Value = global.val * global.a;
}
to
if (string.Equals(a, global.g)) // Static string.Equals prevents a NullReferenceException if 'a' is null
{
MessageBox.Show("a");
//dataGridView1.Rows[global.c].Cells[1].Value = global.a;
//dataGridView1.Rows[global.c].Cells[2].Value = global.val * global.a;
}
Generally, you want to use Equals for comparison. ReferenceEquals has some very very specific use cases, and I've only ever had to use it once.
Consider the following code:
public static void Main()
{
string str1 = "abc";
string str2 = "abc";
if (str1 == str2)
{
Console.WriteLine("True");
}
else
{
Console.WriteLine("False");
}
Console.ReadLine();
}
The output is "True". string is a reference type in .Net & I am comparing two different objects, but still the output is "True".
Is is because it internally calls ToString() method on both objects & before comparing them?
Or is it because a string is an immutable type? Two completely distinct string objects having the same value would point to same memory location on the heap?
How does string comparison happens?
How does memory allocation works on the heap? Will two different string objects with the same value point to same memory location, or to a different one?
Strings are compared by value by default.
Objects are compared by reference by default.
Identical string literals in the same assembly are interned to be the same reference.
Identical strings that are not literals can legally be interned to the same reference, but in practice typically are not.
So now you should be able to understand why you get the given output in this program fragment:
string a1 = "a";
string a2 = "a";
string aa1 = a1 + a2;
string aa2 = a1 + a2;
object o1 = a1;
object o2 = a2;
object o3 = aa1;
object o4 = aa2;
Console.WriteLine(a1 == a2); // True
Console.WriteLine(aa1 == aa2); // True
Console.WriteLine(o1 == o2); // True
Console.WriteLine(o3 == o4); // False
Does that make sense?
For the string type, == compares the values of the strings.
See http://msdn.microsoft.com/en-us/library/53k8ybth.aspx
Regarding your question about addressing, a few lines of code says they will have the same address.
static void Main(string[] args)
{
String s1 = "hello";
String s2 = "hello";
String s3 = s2.Clone() as String;
Console.Out.WriteLine(Get(s1));
Console.Out.WriteLine(Get(s2));
Console.Out.WriteLine(Get(s3));
s1 = Console.In.ReadLine();
s1 = Console.In.ReadLine();
s3 = s2.Clone() as String;
Console.Out.WriteLine(Get(s1));
Console.Out.WriteLine(Get(s2));
Console.Out.WriteLine(Get(s3));
}
public static string Get(object a)
{
GCHandle handle = GCHandle.Alloc(a, GCHandleType.Pinned);
IntPtr pointer = GCHandle.ToIntPtr(handle);
handle.Free();
return "0x" + pointer.ToString("X");
}
Results in the same address for each set of tests.
Get() courtosey of Memory address of an object in C#
String Class has done operator overloading to write custom logic for == operator.
That's why when == is used in case of string it does not compare references but actual value.
Please see https://stackoverflow.com/a/1659107/562036 for more info
It's entirely likely that a large portion of the developer base comes
from a Java background where using == to compare strings is wrong and
doesn't work. In C# there's no (practical) difference (for strings).
string is reference type, because its does not have default allocation size, but is treated as a value type for sanity reasons, could you image a world were == would not work between to exact string values.
Is it possible to assign by reference? I know that ref has to be used in methods.
string A = "abc";
string B = A;
B = "abcd";
Console.WriteLine(A); // abc
Console.WriteLine(B); // abcd
Can I have some sort of
string A = "abc";
string B = (ref)A;
B = "abcd"; // A was assigned to B as reference, so changing B is the same as changing A
Console.WriteLine(A); // abcd
Console.WriteLine(B); // abcd
That's how it works already. Strings are a reference type- your variable A is a reference (like a pointer) to a string on the heap, and you are just copying the pointer's value (the address of the string) into the variable B.
Your example doesn't change the value of A when you assign "abcd" to B because strings are treated specially in .net. They are immutable, as Kevin points out- but it is also important to note that they have value type semantics, that is assignments always result in the reference pointing to a new string, and doesn't change the value of the existing string stored in the variable.
If, instead of Strings, you used (for example) cars, and changed a property, you'd see this is the case:
public class Car {
public String Color { get; set; }
}
Car A = new Car { Color = "Red" };
Car B = A;
B.Color = "Blue";
Console.WriteLine(A.Color); // Prints "Blue"
// What you are doing with the strings in your example is the equivalent of:
Car C = A;
C = new Car { Color = "Black" };
It's probably worth noting that it does not work this way for value types (integers, doubles, floats, longs, decimals, booleans, structs, etc). Those are copied by value, unless they are boxed as an Object.
You aren't modifying the reference to A. You are creating a whole new string. A still shows "abc", because it can't be changed by modifying B. Once you modify B, it points to a whole new object. Strings are immutable too, so any change to one creates a new string.
To further answer your question with non-immutable reference types, it is possible to modify the properties of an object that a variable points to and it will show the changed effect when you access other variables pointing to the same object. This does not mean however that you can have a variable point to a brand new object, and have other variables (that pointed to the old object) point to that new object automatically without modifying them as well.
Strings are immutable that's true. However you can resolve your issue by encapsulating string within a class and making A and B instances of that class. Then A = B should work.
public class ReferenceContainer<T>
{
public T Value {get;set;}
public ReferenceContainer(T item)
{
Value = item;
}
public override string ToString()
{
return Value.ToString();
}
public static implicit operator T (ReferenceContainer<T> item)
{
return Value;
}
}
var A = new ReferenceContainer<string>("X");
var B = A;
B.Value = "Y";
Console.WriteLine(A);// ----> Y
Console.WriteLine(B);// ----> Y
Strings are already references, after B = A then B.equals(A) will return true. However, when you do B = "abcd" you're doing the same thing, you're assigning B to a reference to the string literal.
What you are wanting to do is modify the data pointed to by the string, however, because Strings in .NET are immutable there is no way to do that.
Strings are special objects in C# because they are immutable, otherwise it would be by reference. You can run this snippet to see.
public class Foo
{
public string strA;
}
Foo A = new Foo() { strA = "abc" };
Foo B = A;
B.strA = "abcd";
Console.WriteLine(A.strA);// abcd
Console.WriteLine(B.strA);//abcd
All you do is this:
string A = "abc";
ref string B = ref A;
B = "abcd"; // A was assigned to B as reference, so changing B is the same as changing A
Console.WriteLine(A); // abcd
Console.WriteLine(B); // abcd
I'm new to Extension Methods and exploring what they can do.
Is it possible for the calling object to be assigned the output without a specific assignment?
Here is a simple example to explain:
public static string ExtensionTest(this string input)
{
return input + " Extended!";
}
In the following examples ...
var foo = "Hello World!";
var foo2 = foo.ExtensionTest(); // foo2 = "Hello World! Extended!"
foo.ExtensionTest(); // foo = "Hello World!"
foo = foo.ExtensionTest(); // foo = "Hello World! Extended!"
... is there any way to get foo.ExtensionTest() to result in "Hello World! Extended!" without specifically assigning foo = foo.ExtensionTest()
No, but the reason that will not work has to do with the immutability of strings, and nothing to do with extension methods.
If instead you had a class:
public class SomeClass
{
public int Value {get; set;}
}
And an extension method:
public static void DoIt(this SomeClass someClass)
{
someClass.Value++;
}
Would have the effect of:
var someClass = new SomeClass{ Value = 1 };
someClass.DoIt();
Console.WriteLine(someClass.Value); //prints "2"
The closest you could get to this (which would be weird) would be to accept an out parameter and use that as the return value:
public static void ExtensionTest(this string input, out string output)
{
output = input + " Extended!";
}
Example:
string foo = "Hello World!";
foo.ExtensionTest(out foo);
The funny thing about that is, while it more closely resembles what you're asking about, it's actually slightly more to type.
To be clear: I don't recommend this, unless it's really important to you to make this sort of method call. The probability of another developer uttering "WTF?" upon seeing it has got to be something like 100%.
What you are seeing is due to strings being immutable.
In any case, you will have to do some sort of assignment if you want the object to change.
The 'this' parameter is passed by value, not by reference. So no, you can't modify the variable in the calling program that is aliased by 'this' in your extension method.
No. Strings in .NET are immutable. All public String methods return new instance of String too.
To assign the new value to your variable inside the extension method, you'd need a ref modifyer on the parameter, which the C# compiler does not permit on extension methods (and it would be a bad idea anyway). It's better to make it clear you're changing the variable.
Use the faster StringBuilder for mutable strings and as pointed out the ref or out keyword. StringBuilder is basically an improved linked-list for strings.
Immutable strings were a design decision to allow close behavior to the C language and many other languages.
string str = "foo";
str += "bar"; // str will be free for garbage collection,
//creating a new string object.
//Note: not entirely true in later C# versions.
StringBuilder sb = new StringBuild();
sb.Append("foo");
sb.Append("bar"); // appends object references to a linked list.
See also:
string is immutable and stringbuilder is mutable
http://en.wikipedia.org/wiki/Linked_list
string a = "a";
string b = a;
string a = "c";
Why does string b still have the value "a" and not "c"?
As string is an object and not a stack value type, what's with this behaviour?
Thanks
You're pointing the variable to something new, it's no different than if you said
Foo a = new Foo();
Foo b = a;
a = new Foo();
// a no longer equal to b
In this example, b is pointing to what a initially referenced. By changing the value of a, a and b are no longer referencing the same object in memory. This is different than working with properties of a and b.
Foo a = new Foo();
Foo b = a;
a.Name = "Bar";
Console.WriteLine(b.Name);
In this case, "Bar" gets written to the screen because a and b still reference the same object.
Let me start by saying that your choices for variables and data are poor. It makes it very difficult for someone to say "the string a in your example..." because "a" could be the content of the string, or the variable containing the reference. (And it is easily confused with the indefinite article 'a'.)
Also, your code doesn't compile because it declares variable "a" twice. You are likely to get better answers if you ask questions in a way that makes them amenable to being answered clearly.
So let's start over.
We have two variables and two string literals.
string x = "hello";
string y = x;
x = "goodbye";
Now the question is "why does y equal 'hello' and not 'goodbye'"?
Let's go back to basics. What is a variable? A variable is a storage location.
What is a value of the string type? A value of the string type is a reference to string data..
What is a variable of type string? Put it together. A variable of type string is a storage location which holds a reference to string data.
So, what is x? a storage location. What is its first value? a reference to the string data "hello".
What is y? a storage location. What is its first value? a reference to the string data "hello", same as x.
Now we change the contents of storage location x to refer to the string data "goodbye". The contents of storage location y do not change; we didn't set y.
Make sense?
why don’t string object refs behave like other object refs?
I deny the premise of the question. String object refs do behave like other object refs. Can you give an example of where they don't?
Part of what confuses people so much about this is thinking of the following as an append operation:
str1 = str1 + str2;
If string were a mutable type, and the above were shorthand for something like this:
str1.Append(str2);
Then what you're asking would make sense.
But str1 = str1 + str2 is not just some method call on a mutable object; it is an assignment. Realizing this makes it clear that setting a = "c" in your example is no different from assigning any variable (reference type or not) to something new.
The below comparison between code that deals with two List<char> objects and code that deals with two string objects should hopefully make this clearer.
var a = new List<char>();
var b = a; // at this point, a and b refer to the same List<char>
b.Add('a'); // since a and b refer to the same List<char> ...
if (b.Contains('a')) { /* ...this is true... */ }
if (a.Contains('a')) { /* ...and so is this */ }
// HOWEVER...
a = new List<char>(); // now a and b do NOT refer to the same List<char>...
if (b.Contains('a')) { /* ...so this is still true... */ }
if (a.Contains('a')) { /* ...but this is not */ }
Compare this with a slightly modified version of the code you posted:
string a = "a";
string b = a; // at this point, a and b refer to the same string ("a")...
if (b == "a") { /* ...so this is true... */ }
if (a == "a") { /* ...and so is this */ }
// REMEMBER: the below is not simply an append operation like List<T>.Add --
// it is an ASSIGNMENT
a = a + "c"; // now they do not -- b is still "c", but a is "ac"
if (b == "a") { /* ...so this is still true... */ }
if (a == "a") { /* ...but this is not */ }
In .Net, a, b and c are reference to the objects and not the objects themselves. When you reset a, you are pointing this reference to a new memory location. The old memory location and any references to it are unchanged.
I guess the OP thinks string objects to be mutable, so something like var = "content";
would actually store the new character array inside the already existing object.
String is, however, an immutable type, which means that in this case a new string object is created and assigned to var.
See for example:
http://codebetter.com/blogs/patricksmacchia/archive/2008/01/13/immutable-types-understand-them-and-use-them.aspx
It is a misunderstanding because of the builtin string support of c#.
string a = "123"; //The way to write it in C#
string a = new string("123"); //Would be more obvious
The second way to define a is more obvious what happens, but it is verbose.Since strings have direct support from the compiler calling the string constructor is unnecessary.
Writing your example verbose:
string a = new string("a");
string b = a;
string a = new string("c");
Here the behavior is as expected a gets a reference to the new string object assigned. while the reference held by b still points to the old string.