如何获取可变字符串列表?
我有以下代码
List l = new List(); String s = "hello"; l.Add(s); s = "world";
当我设置一些断点并完成程序时,在执行最后一行之后,列表中的值仍然是hello
而不是world
。
它不应该等于world
吗? 字符串不是一个对象,我不只是将一个指针插入列表中吗? 稍后如果我将字符串更改为指向不同的值(“world”),为什么我的列表仍然引用旧值?
我怎样才能达到理想的效果? 非常感谢!
字符串是不可变的,因此不起作用。 当您尝试设置它时,实际上是将指针放到旧字符串上并在引擎盖下创建一个新字符串。
要获得所需的效果,请创建一个包装字符串的类:
public class SortOfMutableString { public string Value {get;set;} public SortOfMutableString(string s) { Value = s; } public static implicit operator string(SortOfMutableString s) { return s.Value; } public static implicit operator SortOfMutableString(string s) { return new SortOfMutableString(s); } }
并在列表中使用它。 然后引用将指向类,但您可以在其中包含字符串值。 为了使它更好,请覆盖与字符串之间的implicit
强制转换,这样您甚至不需要看到您正在与SortOfMutableString
。
请参阅Jon Skeet的回答毫无疑问是对C#中字符串的非常准确的解释,我甚至都不打扰!
替代类名:
- PseudoMutableString
- ICantBelieveItsNotMutable
- HappyAndReferenceableString
您正在更改s
引用以引用其他String
实例。
字符串是不可改变的; 无法更改添加到列表中的现有实例。
相反,您可以使用可写的String
属性创建可变StringHolder
类。
不,它不应该等于world
。 变量s
的值是参考。 当您调用l.Add(s)
,该引用l.Add(s)
值传递给列表。 所以列表现在包含对字符串“hello”的引用。
您现在将s
的值更改为对字符串“world”的引用。 这根本不会改变列表。
区分三个非常不同的概念很重要:
- 变量(具有名称和值)
- 引用(允许您导航到对象的值,或
null
) - 一个东西
所以特别是,列表对变量 s
一无所知 – 它知道传递给Add
的值 ; 那个值碰巧是在调用Add
时的s
值,就是这一切。
您可能会发现这些文章很有用:
- 值和引用
- 参数传递C#
不,涉及两个不同的参考。 一个叫做s
,一个叫做List[0]
。 当您说l.Add(s)
您将列表引用设置为与s
相同的地址时,但是当您将s
指定给“world”时,则s
将指向新字符串,而List[0]
指向旧字符串。
如果你真的想要做你喜欢的事情,你需要将字符串包装在另一个包含字符串的对象中,这样s
和List[0]
都引用该对象,然后该对象引用一个字符串可以改变,两者都会看到它。
public class StringWrapper { public string TheString { get; set; } }
然后你可以这样做:
var s = new StringWrapper { TheString = "Hello" }; var l = new List(); l.Add(s); s.TheString = "World";
而现在l[0].TheString
也将成为世界。 这是有效的,因为在这种情况下我们不会更改List [0]或s中的引用,而是它们由s和List [0]引用的对象的内容。
变量是对象引用 ,而不是对象本身。 s = "world"
表示“make s
引用字符串"World"
) – 它不会以任何方式影响s
先前引用的字符串"hello"
。此外,C#中的字符串总是不可变的。但是,你可以,使第一个列表元素(当前引用"hello"
)引用不同的字符串: l[0] = "world"
。
这里的另外两个答案很好地说明了你为什么尝试没有“工作,但你正在寻找一个解决方案,以达到你想要的效果。 将字符串(属性)包装在对象内部。 然后你可以改变那个字符串,它将反映在集合中。