 Welcome to Strings in the .NET Framework. In this learning activity, you'll learn how strings are implemented in the .NET Framework. When working with strings in C-sharp, it's important to realize what is happening under the hood. Otherwise, your application may have some unintended side effects. The string data type in C-sharp has some behaviors which aren't apparent at first. When writing C-sharp code, you can treat string variables just as you would any primitive variable. For example, say you start with a string variable and set it to the value something, then you declare another string variable and set it equal to the first. Later, if you decide to change the first variable's value, it won't have any effect on the second variable's value. This code behaves as if it were written using a primitive data type, such as an integer. The integer type, like all C-sharp primitive types, is a value type. A value type means the value is assigned to the variable itself. So in the last example, the value of 100 is assigned to the int1 variable. The next line of code assigns int1 to a new integer variable called int2. Since integers are value types, this really means the code assigns the current value of int1, 100, to the int2 variable. Therefore, the int2 variable also holds a value of 100. Then we assign a value of 50 to int1. Assigning a different value to int1 doesn't affect the assignment of any other variables. Therefore, the value of int2 remains 100. In our code, we have two integer variables declared. Our code allocates memory in the stack to store these variables. Since integers are value types, this means the integer values are stored with the variables in stack memory. If we go back to the first piece of code, it certainly looks like the same thing happened with our strings. And it effectively is. However, the technicalities under the hood are a bit different. The string type may appear to behave and act like the primitive types, but it is in fact much different. First, it's important to realize the string type is a reference type, not a value type. Reference types are not stored on the stack with the variable they're assigned to. Instead, reference types are stored in heap memory. What is stored with the variable on the stack is a reference to the actual value. The first line of code creates a new string. The string has the value something. Since strings are reference types, it's stored in the heap, not the stack. Therefore, our code allocates space somewhere in heap memory and stores something there. It then assigns a reference to that value to the string1 variable. The second line of code assigns string2 to string1. This time, the code won't create another string. Instead, it simply creates another reference to the same string value that the variable string1 refers to. This new reference is then assigned to the string2 variable. The next line of code creates a new string with the value of something else. This allocates enough space in the heap to store something else and assigns a reference to this new string to string1. It's important to remember strings are immutable. Immutable simply means they can't change, so you can't change a string once it's defined. Notice a new string is created to store something else. The existing string containing something is not modified. The immutability of strings makes them behave as if they were value types. This makes writing code using strings much more natural because they behave as expected. If strings were not immutable and in the past example the string value of something was changed to something else, then both string variables string1 and string2 would be equal to something else. This would be a strange and undesirable side effect when writing code using string types. The immutability of strings has some other not-so-nice side effects in certain situations. One such issue is with the concatenation of strings. Since string values can't change after they're created, concatenating one string to an existing string always results in the creation of a new string. A common example is displaying someone's full name when the person's first and last names are stored in two different variables. If the first name variable is given the value of Fred and the last name variable is given the value of Flintstone, when we concatenate the two strings together, we get a third string containing the value Fred Flintstone. This is pretty straightforward. In this example, we use three variables and three string values to get the full name. However, the resulting value squishes the first name and the last name together. Usually, we would want to add a space between the first and last name. Let's change the previous code to do just that. How many strings are used now? You might guess it's three strings, since there are still only three string variables. You might also guess four strings because we're using an additional string to hold the space between the first and last names. Regardless if you've guessed three or four, you're incorrect. This bit of code actually uses five strings to get our value, because strings are immutable, so we can't change any of our strings. We're using the strings Fred, Flintstone, a space, and a string to hold onto the results. So where is the fifth string? It has to do with string concatenation. String concatenation is a strictly binary operation. Binary in this case doesn't mean we have to think about the ones and zeros that make up pretty much everything in the computer. A binary operation is a simple operation that works with two inputs resulting in a single outcome. For example, addition 1 plus 1 equals 2. This means in the line of code where we concatenate the strings together, we actually concatenate two strings together twice. First, we concatenate first name with the space string literal, which results in a new string created on the heap. This new intermediate string is then concatenated with last name, which results in another new string. This time, the resulting string is also assigned to the full name variable. Notice how during this process two additional strings are allocated in heap memory even though they aren't assigned to any variable. Whenever a string is allocated in the heap, the system uses some memory to store it. Technically, a string is a collection of char objects. Each char object occupies two bytes in memory. So how many bytes in memory does a string occupy? A string occupies two times the number of characters, plus some overhead, about 20 bytes. The .NET framework limits the string size to 2 gigabytes, which is about 1 billion characters. In our previous example, we stored an intermediate string with the value of Fred. The string used additional resources from the system. In this situation, we allocated an additional 30 bytes for this intermediate string. Do we really need to be concerned about this additional memory? Unless you're coding in some specific conditions, such as an embedded system, this amount is negligible. Also, since the .NET framework uses a garbage collector, the additional 30 bytes are freed by the garbage collector sometime after our method returns. Typically, the additional space needed for intermediate values isn't of much concern, as the amount of space allocated is negligible. However, there are several gotcha situations where string concatenation needs to allocate considerably larger amounts of memory for intermediate values, that can quickly use all of the system's memory. Usually these gotcha situations happen when looping over a collection and building a string from that collection. Congratulations! You've completed strings in the .NET framework.