Patrick
Patrick

Reputation: 884

String instance behavior different than object

string is an reference type (similar to object). Why the diff behavior in the following scenario - when creating an instance of string and object?

I understand the concept of immutability etc in string but that is to do with value assigned to string (which wont change). My question is more to do with why s2 is creating another complete instance whereas if i had done with object it doesnt do that?

enter image description here

Example of string

class Program
{
    static void Main(string[] args)
    {
        string s1 = "Hello";
        string s2 = s1;

        s1 = null;
        Console.WriteLine("s1 = " + s1);
        Console.WriteLine("s2 = " + s2);
        Console.ReadLine();
    }
}

Output: s2 still prints "Hello"

Example of object

class Program
{
    static void Main(string[] args)
    {
        Name s1 = new Name();
        s1.id = 5;
        Name s2 = s1;

        s1 = null;
        Console.WriteLine("s1 = " + s1.id);
        Console.WriteLine("s2 = " + s2.id);
        Console.ReadLine();
    }
}

public class Name
{
    public int id { get; set; }
}

Output: Both s1 and s2 are null;

Upvotes: 3

Views: 275

Answers (3)

BenVlodgi
BenVlodgi

Reputation: 2185

First of all, I'm sure you realize you are going to get a lot of NullReferenceException with that code you've got there. Secondly, the string class is a fun and special object which you can mentally think of as a primitive data type. Let me just say though, System.String is not a primitive type.... but you can think about it like it is for general purposes.

I have drawn some diagrams that may better display what is going on in each of the examples you gave.

When you

string s1 = "Hello";
string s2 = s1;

An object named s1 of type string is created which points to a memory space that holds the value "Hello". Then a new object of type string named s2 is created and the value of "Hello" from s1 is copied to another memory space and addressed by s2. This results in your memory looking as it does below.

enter image description here

Now, when you

s1 = null;

You have set the reference of s1 to point to the null pointer, which leaves that memory with the value of "Hello" to float around until the garbage collector comes around and removes it. At this point s1 is still pointing to the value that was copied earlier.

enter image description here


Now lets look at how this differs from a normal object.

When you

Name s1 = new Name();
s1.id = 5;
Name s2 = s1;

A memory space called s1 is created which points to a newly allocated space in memory the large enough to hold the memory of a Name object.

Then you pointed to the memory space addressed in s1 and changed its Property called id to be 5.

Then you created a new memory space called s2 which copies the value of the address to the allocated memory mentioned above. So now s1 and s2 point to the same object in memory. This results in your memory looking as it does below.

enter image description here

Note: That at this point, if you were to change the value of id it would change for both s1 and s2, and if that was nullable type you were using for id, and you set it to be null, the change would be reflected in both s1 and s2.

Now if you were to

s1 = null;

as you did in your post. s1 would change its address to point to the null pointer, and s2 would continue to be looking at the same space in memory. Which results in what you see below.

enter image description here


Edit: To provide further explanation on why strings seem to behave like primitives and not like objects. I don't know, however I will speculate. My guess is that it was designed this way because developers want to use string as if it were a primitive. I will say that it is so nice to not have to worry about stray references to my string, or having to clone it before I make changes to it. However Microsoft could not make string a primitive type because strings are huge. The max length of a string is the maximum value of an Int32. And every letter is a char which is a Int16, so that is somewhere around 2 gigs I believe (don't quote my math). This means that strings are too big to store on the stack which is only 1MB. Thus strings have to be objects and placed on the heap.

If you are unaware of the differences between the stack and the heap, I do recommend looking it up, it is good to know how memory is handled, while in C# all that dirty work is done for you, if you decide to move to something like C++ you'll find yourself managing that on your own (not super fun).

So in short I suppose it is because we want to use strings like primitives, but they are implemented as objects because of the limitations of the stack.

Upvotes: 6

Selman Genç
Selman Genç

Reputation: 101681

In your second code snippet, s2 is not null but you can't see it because s1.id throws NullReferenceException and you didn't handle it.So your program never reaches the second line.Remove it and you will see 5 in the Console.After s1 = null;, s2 doesn't change.It is still pointing the s1's old Location in the memory.

Also if you don't want to remove the first line alternatively you can put it inside of try/catch block:

try
{
    Console.WriteLine("s1 = " + s1.id);
}
catch (Exception ex)
{
     Console.WriteLine(ex.Message);
}
 Console.WriteLine("s2 = " + s2.id);

And you can see 5 in the Console and the exception message.But this is completely unnecessary; it will definitely throw exception because s1 is null.So, as a result: there is no difference between string and other reference types except immutability

Upvotes: 7

NathanAldenSr
NathanAldenSr

Reputation: 7961

Your variables are reference variables because they are declared with the String type. Your code is doing this:

  1. Retrieve a reference to the string Hello
  2. Assign that reference to the string variable s1
  3. Create a new variable s2 and assign its reference to the reference in s1
  4. Assign s1's reference to null

Throughout this process, the string Hello is still in memory and s2 still references it. s1 and s2 are two different containers; they can each hold their own reference. Whether the reference is the same is immaterial.

I'll try a metaphor:

You (s2) and I (s1) are sitting in a room looking at a vase (Hello) on a table. This is akin to s1 and s2 pointing to the same string in memory, as they do after the second line in your Main method. Now, I get up and leave the room (s1 = null;) You're still looking at the vase, aren't you? We are two different people (variables) with the capacity to look at different things.

Upvotes: 1

Related Questions