我有以下代码
List<String> l = new List<String>();
String s = "hello";
l.Add(s);
s = "world";
当我设置一些断点并完成程序时,在执行最后一行后,列表中的值仍然是hello
而不是world
。
它不应该等于world
吗?字符串不是一个对象,我不只是将一个指针插入列表中吗?稍后如果我将字符串更改为指向不同的值(“world”),为什么我的列表仍然引用旧值?
我怎样才能达到理想的效果? 非常感谢!
答案 0 :(得分:5)
字符串是不可变的,所以不起作用。当您尝试设置它时,实际上是将指针放到旧字符串上并在引擎盖下创建一个新字符串。
要获得所需效果,请创建一个包装字符串的类:
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#中字符串的非常准确的解释,我甚至都不打扰!
替代课程名称:
答案 1 :(得分:4)
您正在更改s
引用以引用其他String
实例
字符串是不可改变的;无法更改添加到列表中的现有实例。
相反,您可以创建一个具有可写StringHolder
属性的可变String
类。
答案 2 :(得分:3)
不,它不应该等于world
。变量s
的值是引用。当您致电l.Add(s)
时,该引用会按值传递给列表。所以列表现在包含对字符串“hello”的引用。
现在,您将s
的值更改为对字符串“world”的引用。这根本不会改变列表。
区分三个截然不同的概念非常重要:
null
)所以特别是,列表对变量 s
一无所知 - 它知道传递给{{1}的值 };那个值发生是调用Add
时s
的值,这就是全部。
您可能会发现这些文章很有用:
答案 3 :(得分:1)
不,涉及两个不同的参考。一个叫s
,一个叫List[0]
。当您说l.Add(s)
时,您将列表引用设置为与s
相同的地址,但是当您将s
分配给“世界”时,s
将指向新字符串,让List[0]
指向旧字符串。
如果你真的想要做一些类似于你所要求的事情,你需要将字符串包装在另一个包含字符串的对象中,以便s
和List[0]
都引用该对象,然后该对象对字符串的引用可以改变,两者都会看到它。
public class StringWrapper
{
public string TheString { get; set; }
}
然后你可以这样做:
var s = new StringWrapper { TheString = "Hello" };
var l = new List<StringWrapper>();
l.Add(s);
s.TheString = "World";
现在l[0].TheString
也将成为世界。这是有效的,因为在这种情况下,我们不会更改List [0]或s中的引用,而是它们由s和List [0]引用的对象的内容。
答案 4 :(得分:0)
变量是对象引用,而不是对象本身。 s = "world"
说“make s
引用字符串"World"
” - 它不会以任何方式影响"hello"
之前引用的字符串s
。 ,C#中的字符串总是不可变的。但是,您可以使第一个列表元素(当前引用"hello"
)引用不同的字符串:l[0] = "world"
。
答案 5 :(得分:0)
这里的另外两个答案很好地说明了你为什么尝试没有“工作,但你正在寻找一个解决方案,以达到你想要的效果。将字符串(属性)包装在对象内部。然后你可以改变那个字符串,它将反映在集合中。