开发者

if strings are immutable in c#, how come I am doing this?

I read today, in c# strings are immutable, like once created they cant be changed, so how come below code works

string str="a";
str +=开发者_JAVA技巧"b";
str +="c";
str +="d";
str +="e";

console.write(str) //output: abcde

How come the value of variable changed??


String objects are immutable, but variables can be reassigned.

You created separate objects

a
ab
abc
abcd
abcde

Each of these immutable strings was assigned, in turn, to the variable str.

You can not change the contents (characters inside) a string.

Changing the variable is a different thing altogether.


It is easy to show that the post did not mutate the String object as believed:

string a = "a";
string b = a;
Console.WriteLine(object.ReferenceEquals(a, b)); // true
Console.WriteLine(a); // a
Console.WriteLine(b); // a
b += "b";
Console.WriteLine(object.ReferenceEquals(a, b)); // false
Console.WriteLine(a); // a
Console.WriteLine(b); // ab

The is because the x += y operator is equivalent to x = x + y, but with less typing.

Happy coding.


Use reflector to look at the ILM code and you will see exactly what is going on. Although your code logically appends new contents onto the end of the string, behind the scenes the compiler is creating ILM code that is creating a new string for each assignment.

The picture gets a little muddier if you concatenate literal strings in a single statement like this:

str = "a" + "b" + "c" ...

In this case the compiler is usually smart enough to not create all the extra strings (and thus work for the Garbage collector and will translate it for you to ILM code equivalent to:

str = "abc"

That said, doing it on separate lines like that might not trigger that optimization.


Immutable means the memory location used to store the string variable never gets changed.

string str ="a";  //stored at some memory location
str+= "b";  // now str='ab' and stored at some other memory location
str+= "c";  // now str='abc' and stored at some other memory location

and so on...

Whenever you change the value of string type, you never actually store the new value at the original location, rather keep storing it at new memory locations.

string a="Hello";
string b=a;

a="changed";

console.writeline(b); 

Output

Hello // variable b still referring to the original location.

Please check John Skeet's page

http://csharpindepth.com/Articles/General/Strings.aspx


Concepts:

The variable and the instance are separate concepts. A variable is something that holds a value. In the case of a string, the variable holds a pointer to that string that is stored somewhere else: the instance.

A variable can always be assigned and reassigned if you want... it is variable after all! =)

The instance, that I told is somewhere else, can not be changed in the case of a string.

By concatenating strings like you did, you are in fact creating a lot of different storages, one for each string concatenation.

The correct way to do it:

To concatenate string, you can use StringBuilder class:

StringBuilder b = new StringBuilder();
b.Append("abcd");
b.Append(" more text");
string result = b.ToString();

You could also use a list of string, and then join it:

List<string> l = new List<string>();
l.Add("abcd");
l.Add(" more text");
string result = string.Join("", l);


@pst - I agree that readability is important, and in most cases on a PC it won't matter, but what about if you're on a mobile platform where system resources are constrained?

It's important to understand that StringBuilder is the best way to concat strings. It is much faster and more efficient.

You highlighted the important difference, though, as to whether it is significantly faster, and in what scenarios. It is illustrative that the difference has to be measured in ticks at low volumes, because it can't be measured in milliseconds.

It's important to know that for everyday scenarios on a desktop platform, the difference is imperceptible. But it's also important to know that for mobile platforms, edge cases where you're building large strings or doing thousands of concats, or for performance optimization, StringBuilder does win. With a very large number of concats, it is worth noting that StringBuilder takes slightly more memory.

This is by no means a perfect comparison, but for the fool that concats 1,000,000 strings, StringBuilder beats plain string concatenation by ~10 mins (on a Core 2 Duo E8500 @ 3.16GHz in Win 7 x64):

String concat   (10):           9 ticks,        0 ms,           8192 bytes
String Builder  (10):           2 ticks,        0 ms,           8192 bytes
String concat   (100):          30 ticks,       0 ms,           16384 bytes
String Builder  (100):          6 ticks,        0 ms,           8192 bytes
String concat   (1000):         1658 ticks,     0 ms,           1021964 bytes
String Builder  (1000):         29 ticks,       0 ms,           8192 bytes
String concat   (10000):        105451 ticks,   34 ms,          2730396 bytes
String Builder  (10000):        299 ticks,      0 ms,           40624 bytes
String concat   (100000):       15908144 ticks, 5157 ms,        200020 bytes
String Builder  (100000):       2776 ticks,     0 ms,           216888 bytes
String concat   (1000000):    1847164850 ticks, 598804 ms,      1999804 bytes
String Builder  (1000000):      27339 ticks,    8 ms,           2011576 bytes

Code:

class Program
    {
        static void Main(string[] args)
        {
            TestStringCat(10);
            TestStringBuilder(10);
            TestStringCat(100);
            TestStringBuilder(100);
            TestStringCat(1000);
            TestStringBuilder(1000);
            TestStringCat(10000);
            TestStringBuilder(10000);
            TestStringCat(100000);
            TestStringBuilder(100000);
            TestStringCat(1000000);
            TestStringBuilder(1000000);

            Console.WriteLine("Press any key to exit...");
            Console.ReadKey();
        }

        static void TestStringCat(int iterations)
        {
            GC.Collect();
            String s = String.Empty;
            long memory = GC.GetTotalMemory(true);
            Stopwatch sw = Stopwatch.StartNew();

            for (int i = 0; i < iterations; i++)
            {
                s += "a";
            }

            sw.Stop();
            memory = GC.GetTotalMemory(false) - memory;

            Console.WriteLine("String concat \t({0}):\t\t{1} ticks,\t{2} ms,\t\t{3} bytes", iterations, sw.ElapsedTicks, sw.ElapsedMilliseconds, memory);
        }

        static void TestStringBuilder(int iterations)
        {
            GC.Collect();
            StringBuilder sb = new StringBuilder();
            long memory = GC.GetTotalMemory(true);
            Stopwatch sw = Stopwatch.StartNew();

            for (int i = 0; i < iterations; i++)
            {
                sb.Append("a");
            }

            sw.Stop();
            memory = GC.GetTotalMemory(false) - memory;

            Console.WriteLine("String Builder \t({0}):\t\t{1} ticks,\t{2} ms,\t\t{3} bytes", iterations, sw.ElapsedTicks, sw.ElapsedMilliseconds, memory);
        }
    }


it didn't, it's actually overwriting the variable with the new value creating a new string object each time.


Immutability means that the class cannot be modified. For every += there you are creating a completely new string object.

0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜