tags:

views:

161

answers:

9

I have a class that has 3 string properties. I want to store these in a list so that when I make changes to the strings of the list they also get updated in the class.

This would be easy to do if I was using class object, but string seems to behave differently. It seems to make a copy of the object for the list rather then have a pointer to the object. How am I supposed to do this is C#? If this is not possible is there a better way?

+5  A: 

The problem with strings is that they are immutable. In other words, you can never change a string once it is created.

Thus, if you want to 'change' a string, you must remove the original from the List, and store the result back into the list. Example:

string a = "abcdefg";
List<String> list = new List<String>();
list.add(a);

a = a.Substring(0, 5);

That code does nothing because the string a is pointing to never changes. It just points to a new string.

jjnguy
+3  A: 

In .NET, strings are immutable. If you change the string, you are in fact creating a new one and modifying the reference.

I would consider using a StringBuilder object to address your problem.

Steve Guidi
+1. StringBuilder already does what you want, don't create a new class unless the existing one won't work.
Dour High Arch
StringBuilder will work, but is a poor choice from the POV of performance. The only way to change the value of an instance is to clear it and append the new string, which actually involves copying all those bytes. And if you look at the internals, you'll see it does a second copy when you first call ToString. Also, because changing it involves more than resetting a pointer, it cannot be atomic, so there are possible issues of thread safety.
Steven Sudit
@Steven, please source some evidence for this claim. My StringBuilder tests show only the changed/replaced/appended bytes changing, not "all those bytes". Very few string manipulations involve merely "changing a pointer"; none of the other proposed mutable string classes do this, nor are they atomic. All the other proposals involve creating a new string as well.
Dour High Arch
@Dour, if you look using Reflector, you'll see that it uses a string as a buffer, so when you assign another string to it, it actually has to copy all the bytes from the source. (It also has to recopy them on resizes, but I'm pretty sure it uses a doubling algorithm. But if you take a ToString and then append, it does yet another copy.)On the other hand, assigning an immutable string to the zeroth element of an array is just point manipulation, and it can be atomic.
Steven Sudit
A: 

You're looking for a mutable string of some kind. There are a lot of ways to create a class that behaves the way you want it.

The easiest way would be to use a StringBuilder object instead of a string. You just have to be careful to not make new StringBuilder objects, but rather alter the existing one. Depending on what you need, this may not be the best option.

Alternatively you can create your own wrapper class for String that you can manipulate freely. The downside is you may have to write a lot of stub methods that call down to the inner string depending on how you want to use it. It would be easier to just expose a read/write string property. This has the advantage of letting you define exactly what behaviours you want, but will take longer to write in the first place. Again, you'll have to make sure to not create new instances of the wrapper class, but rather just alter the class's internal string.

Welbog
A: 

Wrap your string into a custom class, this will allow you to share it amongst a number of different locations. You could also choose to store Char arrays instead.

David Rutten
I would think that, if all you need is a level of indirection, a custom class is overkill.
Steven Sudit
+2  A: 

Since strings are immutable, the simplest work-around is to instead store the reference to a string array with one element. Replacing that element will then be noticed by anyone with a reference to the array.

Steven Sudit
+2  A: 

Strings in C# are immutable, so you cannot change a string in C# - you can only create new strings.

You could rather store a class that has a string member

class StringHolder {
  public StringHolder(string s) { str = s;} 
  public string str;
}
...
List<StringHolder> l1 = new List<StringHolder>();
List<StringHolder> l2 = new List<StringHolder>();
List<StringHolder> l3 = new List<StringHolder>();

StringHolder h = new StringHolder("Test\n");
l1.add(h);
l2.add(h);
l3.add(h);

h.str = h.str.Replace("\n","");

Now all lists refer to the same StringHolder and will naturally see the same string.

Another option is to store StringBuilder objects in your lists instead of a String.

nos
+3  A: 

Strings are immutable. You can change a reference to point to another string but you cannot modify a string such that other references to it change value as well (except by unsafe, completely dangerous reflective code)

What you want to do is deal with this either through using a mutable alternative, (such as a StringBuilder) or via explicit indirection. I'll show you the latter:

public class Props
{
    private readonly string[] data = new string[2];

    pubic string Foo { get { return data[0]; } }
    pubic string Bar { get { return data[1]; } }

    public IList<string> ModifyValueButNoInsertsList { get { return data;} }
}

Really you should consider actually using string[] rather than IList in this situation as it makes it clear inserts are forbidden, only alterations of the values. Since string[] implements IList<string> this is unlikely to be a problem

ShuggyCoUk
+1  A: 
class StringHolder
{
    public string Value { get; set; }
}

Keep a list of those instead of just strings. Then you can get/set the Value property to update the string value.

Daniel Earwicker
A: 

As a side note (like several have mentioned), if you're doing some heavy processing with strings, use the StringBuilder class. Because of the immutable nature of strings, changing/concatenation of them in loops or what have you - will cause a lot of overhead.

StringBuilder is your friend.

CLR