Explanation to behavior of strings - c#

Objects are reference types; so this code will print out Angelo.
Object o = new Object();
o.Name = "Michael";
Object p = o;
o.Name = "Angelo";
Console.WriteLine(p);
I read that string is a reference type but behaves much like a value type(like int).
int x = 10;
int y = x;
x = 20;
Console.WriteLine(y);
The code above will print 10 because y copies the actual value in the variable x. Now for the string:
string s = "Hello";
string t = s;
s = "Hi";
Console.WriteLine(t);
Now the code above for string will print "Hello". My question is this; since string is a reference type, does string s hold a reference to the object Hello when you declare it?and string t also holds a reference to that object?and the reason why Hi wasn't printed out was because of Immutability?
Or does a string when declared hold the actual value of an object much like value types?like in the second code example.
I want to have a firm grasp of the basics and I am thankful for everyones' patience with the silly questions I post here :)

Let me try to explain line by line what is going on here;
First of all, string is a reference type and reference types have 2 things. An object and a reference to that object.
string s = "Hello";
In this line, you have a "Hello" object and a reference to that object called s.
string t = s;
In this line, you have a reference called t and it refers the same object (which is "Hello") that s refers.
s = "Hi";
In this line, you create a new object called "Hi" and your s reference refers this object now. It doesn't refer the "Hello" object anymore.
Console.WriteLine(t);
Since t still refers to "Hello" object, this string will be printed. Changing the object that s refers doesn't effect it.

and the reason why Hi wasn't printed out was because of Immutability?
No, you are not doing the same thing. If you do:
Object p = o;
p = new Object();
o.Name = "Angelo";
Console.WriteLine(p);
This obviously will not affect the p. So this has nothing to do with immutability. When you assign a new reference, you are throwing away the old one.When you say:
s = "Hi";
It creates a new string object and store it's reference in s.This is default behaviour.
The only exception to this is when you use ref keyword with a reference type parameter it changes it's reference. For example:
void Foo(ref string x)
{
x = "Hi!";
}
string s = "Hello";
Foo(ref s);
// now s is 'Hi!'
Note that if you could change a property of string, you could observe the same behaviour with strings.

You can declare and initialize strings in various ways, as
// Declare without initializing.
string message1;
// Initialize to null.
string message2 = null;
// Initialize as an empty string.
// Use the Empty constant instead of the literal "".
string message3 = System.String.Empty;
The += operator creates a new string that contains the combined contents. That new object is assigned to the variable s1, and the original object that was assigned to s1 is released for garbage collection because no other variable holds a reference to it.
string s1 = "A string is more ";
string s2 = "than the sum of its chars.";
// Concatenate s1 and s2. This actually creates a new
// string object and stores it in s1, releasing the
// reference to the original object.
s1 += s2;
System.Console.WriteLine(s1);
// Output: A string is more than the sum of its chars.
have a look on this link , may solve your issue;
http://msdn.microsoft.com/en-IN/library/ms228362.aspx

Related

Why a reference type doesn't update in C#

Here is my c# code. Why a reference type doesn't update in C#, below is the code
class Program
{
public static void Main(string[] args)
{
var a = A.field;
A.field = "2";
Console.WriteLine(a);
Console.Read();
}
}
public static class A
{
public static string field = "1";
}
The result is 1, why??
public static void Main(string[] args)
{
var a = A.field; // `a` is now a reference to the string "1"
A.field = "2"; // `A.field` is now a reference to the string "2"
Console.WriteLine(a); // nothing else has changed, so `a` is still a reference to the string "1"
Console.Read();
}
So the answer to your question is basically: the reference doesn't update, because you're not changing the reference you're writing to the Console (a), but another reference (A.field).
The behaviour you're witnessing is not limited to reference types. The same thing will happen with value types:
int x = 1;
int y = x;
x = 2; // y is still 1 at this point
This happens because the y variable stores the value 1, and changing value of x does not automatically change the value of y. x doesn't "know" about y.
It is the same with reference types - in your example a points to the same location in memory as A.field after the assignment, but it doesn't "know" where A.field points to. Therefore changing the reference of A.field doesn't influence a.
An analogy:
You give Joe a card with Cat written on it. Let Ann = Joe mean that Ann will receive a card from you with the same thing written on it as on Joe's card. So now they both have Cat written on their cards. Now if you give another card to Joe, with Dog written on it, Ann still has Cat on her card. This analogy applies to value types, for reference types you'd have a location written on the card, pointing to the place where they can find the word. The same principle still applies, though.
This is the same as following:
String a = "1";
String b = a;
b = "2";
Console.Write($"a:{a} b:{b}");
Originally you have a variable a that references the object with the content 1, and a variable b that references the same object. Then you modify the variable b to reference a new object, one with content 2. You do not modify the object referenced by a nor b, you make the variable reference a different object. You would have to modify the object referenced by b so that the a variable 'sees' the change. Alas as String is immutable there is simply no method to actually modify it. Any API at your disposal would result in a new string that b would reference, and a would look the same as before. With a mutable type you would see the difference, as long as you modify the object, not simply assign a new object to the variable:
var a = new Widget {x = 1};
var b = a;
b.x = 2;
Console.Write($"a.x: {a.x} b.x: {b.x}");
You are assigning reference and not modifying the original reference.
When you assign A.field to a you assign reference of string "1" to a. Later you assign a new string to A.field and there was no change in the original value of a. It still holds the old reference to string "1".
If somehow, you could modify the original reference then you should be able to see the change. Since your type is string, you can't really modify it because it is immutable, but consider an example with StringBuilder.
public static class A
{
public static StringBuilder field { get; set; } = new StringBuilder("1");
}
And later.
static void Main(string[] args)
{
var a = A.field;
A.field.Insert(0, "2");
Console.WriteLine(a);
Console.Read();
}
Now you will get modified value "21" in variable a as well.
Notice that the code above is modifying the field with A.field.Insert(0, "2"); and since variable a holds the reference to A.field, you see the change on the next line.
But if you try to assign a new reference to A.field with statement like:
A.field = new StringBuilder("2");
Then A.field will have a new object to reference, and the previous variable a will still keep the old reference.
You may think at a "reference" type variable as a box, where it is into an address to some resource.
Let's consider a string value.. when we assign some literal value string to a "reference", we do nothing that:
to allocate a memory area (static or heap) setted with the specified value;
to allocate another memory area (static or heap) initialized with the memory address (reference) of the string value;
When we assign a string "reference" type var to another "reference", we do nothing that to assign the memory address of the referenced string value to the new "reference".
So, if we change the first "reference" with a new assignment statement, the second will not be affected and it continues to reference the original value.
Finally, it is not possible (for now at least) have "references to references" in C#, you can have it in C++ (where pointers and references are a bit different things..). See also this Eric Lippert answer to an analougous question:
https://stackoverflow.com/a/15328414/3762855
The variable a gets a copy of value of the static property A.field.
So when you modify A.field, the copy does not change.
try this
class Program
{
static void Main(string[] args)
{
A.field = "2";
var a = A.field;
Console.WriteLine(a);
Console.Read();
}
}
public static class A
{
public static string field = "1";
}

C# dictionary value reference type - please explain why this happens

I don't understand the results of the following linqpad query in C#. The comments should explain where I am confused.
void Main()
{
Dictionary<string, testClass> test = new Dictionary<string, testClass>();
string key = "key";
testClass val = null;
test.Add(key, val);
val = new testClass();
test[key].Dump(); //returns null. WHAT? I just set it!!!
test[key] = val;
val.Text = "something";
// returns val object, with Text set to "Something".
// If the above didn't work, why does this work?
test[key].Dump();
val.Text = "Nothing";
// return val object, with Text set to "Nothing".
// This, I expect, but, again, why didn't the first example work?
test[key].Dump();
val = null;
// returns val object, with Text set to "Nothing"...WHAT??
// Now my head is going to explode...
test[key].Dump();
}
// Define other methods and classes here
public class testClass
{
public override string ToString()
{
return Text;
}
public string Text { get; set;}
}
The main reason is that the variable (val) is not the object. It merely contains a reference to an object (or null).
testClass val = null declares a variable of type testClass and sets it to null. It doesn't point to any object.
test.Add(key, val) adds an entry in the dictionary that points to null (note: it doesn't point to val nor does it point to any object).
val = new testClass(); creates a new instance of testClass and val now points to that new object. test[key] is still null and doesn't point to any object.
test[key] = val;
val.Text = "something";
test[key].Dump();
This code points test[key] to the same object that val points to. Again note is it not pointing to val. When you change the object with val.Text = "something" you can see the change using test[key].Dump() because they both point to the same object.
val.Text = "Nothing";
test[key].Dump();
When you set val.Text to the string "Nothing" you can see the change through test[key] for the same reason as above, they both point to the same object.
val = null;
test[key].Dump();
This code sets val to point at null. test[key] still points at the object. Now val and test[key] point to different things.
test.Add(key, val);
val = new testClass();
test[key].Dump(); //returns null. WHAT? I just set it!!!
You are re-instantiating val. It is no longer pointing to the same object that you added to test. When you new up a reference object, it points to a brand new object.
If, say, you had an int property on testClass and did:
var c = new testClass{ MyProperty = 1}
test.Add(key, c);
c.MyProperty = 2;
test[key].MyProperty.Dump();
you would see 2 outputted, because you didn't change the object that c is pointing to, but altered a property on the existing object.
testClass val = null;
test.Add(key, val);
val refers to null. You just added a null to your dictionary, under the key key.
val = new testClass();
You just assigned a new instance of testClass to your variable named val. The dictionary has no way of knowing that you did that. It doesn't know about val; all you gave it was the value that val held at that time. Think of it as keeping a copy of what val held then.
If you put write "4" on a piece of paper and take a photo of it, then you erase it and write "5", the photo still shows "4".
test[key].Dump(); //returns null. WHAT? I just set it!!!
You set test[key] to null, two lines ago. test[key] isn't a reference to "whatever val refers to now"; it's whatever value you passed to the Dictionary.Add() method. That value was null. The dictionary keeps exactly what you gave it, until you give it something else.
test[key] = val;
OK, now you gave it something else. You gave it the new value of val.
val.Text = "something";
// returns val object, with Text set to "Something".
// If the above didn't work, why does this work?
test[key].Dump();
...and that's why this works.
val.Text = "Nothing";
// return val object, with Text set to "Nothing".
// This, I expect, but, again, why didn't the first example work?
test[key].Dump();
The dictionary still has that new value of val -- and val is still referring to that same object (think of it as hanging in space, off the shoulder of Orion). And now you've altered one of the properties of that one object that they both happen to be referring to.
val = null;
Whoops, they're not both referring to the same object any more. The dictionary is still referring to that object, but val is now referring to nothing at all.
// returns val object, with Text set to "Nothing"...WHAT??
// Now my head is going to explode...
test[key].Dump();
And you still haven't given the dictionary anything new, so it still has the last thing you gave it.
Don't feel too bad about this. I taught C# last year to my brother, an MIT PhD in electrical engineering. He got badly snarled in this same issue -- and he's the guy who patiently taught how pointers work in C, back in 1995.
Let me try to explain it in code comments:
void Main()
{
Dictionary<string, testClass> test = new Dictionary<string, testClass>();
string key = "key";
testClass val = null;
//val now holds a null reference
test.Add(key, val);
//You add a null reference to the dictionary
val = new testClass();
//Now val holds a new reference for testClass, while the dictionary still has null
test[key].Dump(); //returns null. WHAT? I just set it!!!
//Now it returns the null reference which you just added to the dictionary
test[key] = val;
//Now the dictionary holds the same reference as val
val.Text = "something";
//You set the Text of the val, and the dictionary-held value, because they're the same
// returns val object, with Text set to "Something".
// If the above didn't work, why does this work?
test[key].Dump();
// I think now you know why..
//...
}
Look at the following code:
List<int> lst = new List<int>();
SomeFunc(lst);
Here is SomeFunc():
void SomeFunc(List<int> l)
{
l = null;
}
Calling SomeFunc() will not change the value of variable lst in any way. This is because l gets a copy of lst. Thus both lst and l point to the same memory object, but both are distinct themselves and changing the contents of one variable has no effect on the value of other.
In a way you can think of reference types as classical pointers, although they are different in many important ways. Having two pointer pointing to the same object doesn't mean those two pointers have any effect on each other's value, and setting one of them to a different value (or null) doesn't change the value of other.
You need to be aware of the difference of value and reference types.
In this case, you have a reference variable with the name val, it's address to the object in the memory is null.
When you are calling "test.Add(key, val);" and val equals null, then there is object behind this reference variable.
In the next line, you initialize the reference variable, now there is a object behind it.
So these results make absolutely sense.
Look here for more information:
Value and Reference Types
C# uses reference types for objects.
1)In the first example you are adding a pair of key and a value which is a reference type. The reference is pointing to null so you actually add (key,null).
2) Now you have created an instance of an object. The val is referencing that object and when you assign it test[key] = val you are actually assigning the object that the val is referencing.
3)The object referenced in the dictionary and the val variable is the same . So you are accessing the same object.
4)You have set the val to null so it doesn't reference anything but in the dictionary it is still referencing to that old object you have created.

C# assign by reference

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

c# strings are reference types - why when i change reference A's value, reference B doesn't change?

If strings in .NET are reference types, in the below code, why doesn't string2 change to "hi" after string1 is changed?
static void IsStringReallyAReference()
{
string string1 = "hello";
string string2 = string1;
Console.WriteLine("-- Strings --");
Console.WriteLine(string1);
Console.WriteLine(string2);
string1 = "hi";
Console.WriteLine(string1);
Console.WriteLine(string2);
Console.Read();
}
/*Output:
hello
hello
hi
hello*/
That is because C# strings are immutable types, meaning that you cannot change the value of the instance.
When you change the string's value you are actually creating a new string and changing the reference to point to the new string after which your two reference variables no longer refer to the same string instance, one refers to the original string while the other refers to the new string instance with the new value.
This image might be helpful for you in order to understand the concept.
That is because Strings are immutable types in .Net, i.e. every time you modify a string a new string is created.
From MSDN
A String is called immutable because
its value cannot be modified once it
has been created. Methods that appear
to modify a String actually return a
new String containing the
modification.
Check the remarks section of this link: http://msdn.microsoft.com/en-us/library/system.string(v=VS.80).aspx
When you assigned "hi" to string1, what happened is that the variable string1 got assigned a new reference to an object on the heap which contains the text "hi".
Whereas, the variable string2 is still holding a reference of the object which has text "hello" within it.

why don't string object refs behave like other object refs?

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.

Categories

Resources