关于在C#中引用字符串的问题

时间:2011-07-02 06:45:37

标签: c# object reference arraylist

快速提问。

采用以下代码示例:

ArrayList arrayList = new ArrayList();
string testString = "";
testString = "test";
arrayList.Add(testString);

在该代码示例中,如果我要执行以下操作:

arrayList[0] = "anotherTest";

将testString更改为anotherText还是保持不变?它是放入的对象还是它的副本,另一个字符串?

谢谢, 基督教

7 个答案:

答案 0 :(得分:4)

之前:

Before

后:

After

  • 只有arrayList [0]的值更改为对“anotherTest”的引用。 testString变量的值保持不变。

  • String是引用类型。这意味着testString变量和arrayList [0]每个(独立地)都拥有对象“test”和“anotherTest”的引用,而不是值本身。

  • 将testString或arrayList [0]从一个字符串更改为另一个字符串不会修改原始字符串。字符串是不可变的。只更改了对字符串对象的引用。

答案 1 :(得分:2)

这里有2个对象:“test”和“anotherTest”。

第1阶段:

arrayList.Add(testString) //Adds the reference stored in testString 
                          //to the end of arrayList.

执行此行后,arrayList [0]还包含对“test”的引用(因为在此阶段,testString包含对象“test”的引用)。

您可以查看:

Console.WriteLine(object.ReferenceEquals(testString, arrayList[0])); //outputs true

第二阶段:

arrayList[0] = "anotherTest"; //stores a reference to the object "anotherTest" in
                              //arrayList[0]

我们根本没有改变testString。它仍然引用“测试”。您可以知道存储在arrayList [0]和testString中的引用是不同的:

Console.WriteLine(object.ReferenceEquals(testString, arrayList[0])); //outputs false

testString - >商店参考“测试”
arrayList [0] - >存储引用“anotherTest”

答案 2 :(得分:2)

完成第一个代码块后

 ArrayList arrayList = new ArrayList(); 
 string testString = "";
 testString = "test";
 arrayList.Add(testString);

您有两个引用arrayList,一个引用testString

arrayList中的第一个元素引用与testString相同的对象,即值为"test"的字符串。

arraylist确实包含对testString对象的引用,但是arraylist item 0和testString变量都引用了同一个对象。

执行作业时

    `arrayList[0] = "anotherTest";`

您隐式实例化包含string的新"anotherTest"对象。此对象存储在索引为null的数组项中。

所以在第二个块之后,arraylist第0项引用了新的字符串对象,testString继续引用原始字符串。

答案 3 :(得分:1)

在您的示例中,您正在更新列表的第一个索引,而不是添加到列表中的原始字符串。

即使你没有使用字符串,例如Bitmap类,甚至是int结构:

int i = 14;

List<int> myList = new List<int>();
myList.Add(i);

myList[0] = 3;

这不会影响原始i,它将保持为14。

另一件事你应该知道字符串类 - 通常不像其他类 - 是不可变的所以:

string s1 = "some text";
string s2 = s1;
s2 += " another text";

s1将保持不变。

普通类不会是不可变的,例如:

class MyClass
{
    public string MyString;
}

MyClass class1 = new MyClass();
class1.MyString = "Some String";
MyClas class2 = class1;
class2.MyString = "Other String";

这将影响class1字符串,因此它现在是“Other String”,因为这些类是referance类型。

答案 4 :(得分:0)

事实上,到目前为止,三个答案中没有一个是非常准确的。

testString变量始终在示例中保存对“test”的引用。 它永远不会改变。

更重要的是ArrayList也是一个包含对象引用的容器。因此,当您将“anotherTest”分配给第0个元素时,实际上使第0个元素引用为不同的字符串对象。这不会改变testString的值。

答案 5 :(得分:-1)

好吧,你总是可以运行代码来查找;)。

答案是testString不会改变。 @ dtb的答案解释了原因。我将解决问题的另一个方面,关于你的“是放入的对象还是它的副本,另一个字符串?”问题

让我们分解代码中的内容:

  • testString包含对"test"
  • 的引用
  • 致电arrayList.add(testString)arrayList[0]作为对"test"的引用。
  • 执行arrayList[0] = "anotherTest"设置arrayList[0]作为对"anotherTest"的引用。

所以,正如你所看到的,永远都没有复制。字符串不会被复制,或者(正如其他一些答案所说的那样)“按值传递”。


如果您的问题是关于值类型,例如struct甚至只是int,那么答案仍然那个{ {1}}未更改,但在 情况下,原因是复制已经发生:值类型 “按值传递”,并且它们的副本确实得到了使用testInt运算符时创建。

答案 6 :(得分:-2)

对你的问题的简短回答是“不”。

为什么呢? 因为字符串是不可变的。

原因如下:

来自维基百科:

  

如果已知某个对象是不可变的,   它可以简单地通过制作来复制   引用它的副本而不是   复制整个对象。    - Wikipedia.org

我们来看一个例子:

var a = "Testing";
var b = a;

在这里,你已经有一个字符串(“Testing”)坐在内存中的某个位置(假设位置为0x001。所以,“a”的实际值在第一行变为0x001。

我们在第二行设置b = a ...所以b也设置为0x001(因为我们正在复制引用)。

现在,假设我们这样做:

a = "Again";

这里,我们有另一个字符串(“Again”)坐在内存中的某个不同位置(假设位置为0x022)。

我们知道字符串是不可变的...所以这里发生了什么?嗯......这意味着我们通过引用分配。因此,“a”的值变为0x022。

这对“b”意味着什么?

这意味着,任何指向0x001(“Testing”)的变量都将STILL指向0x001 ...因此,在这种情况下,“b”仍然是UNCHANGED。

只有通过更改引用更新的“a”才会指向0x022。