C# 奇怪的对象行为

标签 c# .net class object reference

在处理自定义对象时,我注意到 C# 中的一些东西我觉得有点奇怪。我敢肯定这只是我缺乏理解,所以也许有人可以启发我。

如果我创建一个自定义对象,然后将该对象分配给另一个对象的属性,而第二个对象修改分配给它的对象,即使没有返回任何内容,这些更改也会反射(reflect)在进行分配的同一个类中。

你想要英文版的吗?这是一个例子:

class MyProgram
{
    static void Main()
    {
        var myList = new List<string>();
        myList.Add("I was added from MyProgram.Main().");
        var myObject = new SomeObject();
        myObject.MyList = myList;
        myObject.DoSomething();

        foreach (string s in myList)
            Console.WriteLine(s); // This displays both strings.
    }
}

public class SomeObject
{
    public List<string> MyList { get; set; }

    public void DoSomething()
    {
        this.MyList.Add("I was added from SomeObject.DoSomething()");
    }
}

在上面的示例中,我会这么认为,因为 SomeObject.DoSomething()返回 void,该程序将只显示 "I was added from MyProgram.Main()." .然而,List<string>实际上同时包含该行和 "I was added from SomeObject.DoSomething()" .

这是另一个例子。在此示例中,字符串保持不变。有什么区别,我错过了什么?

class MyProgram
{
    static void Main()
    {
        var myString = "I was set in MyProgram.Main()";
        var myObject = new SomeObject();
        myObject.MyString = myString;
        myObject.DoSomething();

        Console.WriteLine(myString); // Displays original string.
    }
}

public class SomeObject
{
    public string MyString { get; set; }

    public void DoSomething()
    {
        this.MyString = "I was set in SomeObject.DoSomething().";
    }
}

此程序示例最终显示 "I was set in MyProgram.Main()" .在看到第一个示例的结果后,我会假设第二个程序会用 "I was set in SomeObject.DoSomething()." 覆盖字符串。 .我想我一定是误会了什么。

最佳答案

这并不奇怪,也不奇怪。当你创建一个类时,你就创建了引用类型。当您传递对对象的引用时,持有该对象引用的任何人都可以看到对它们引用的对象所做的修改。

var myList = new List<string>();
myList.Add("I was added from MyProgram.Main().");
var myObject = new SomeObject();
myObject.MyList = myList;
myObject.DoSomething();

所以在这段代码中,您实例化了一个新的 List<string> 实例。并将对该实例的引用分配给变量 myList .然后你添加 "I was added from MyProgram.Main()."myList 引用的列表.然后,您将对同一列表的引用分配给 myObject.MyList (明确地说,myListmyObject.MyList 指的是相同的 List<string> !然后调用 myObject.DoSomething()"I was added from SomeObject.DoSomething()" 添加到 myObject.MyList 。因为 myListmyObject.MyList 都指的是同样的 List<string> ,他们都会看到这个修改。

我们打个比方。我有一张纸,上面有电话号码。我复印那张纸给你。我们都有一张纸,上面有相同的电话号码。现在我拨通那个号码,并告诉电话另一端的人在他们的房子上张贴横幅,上面写着"I was added from MyProgram.Main()."。你调用电话另一端的人,让他们在他们的房子上张贴横幅,上面写着"I was added from SomeObject.DoSomething()"。 .好吧,住在有那个电话号码的房子里的人现在将在他们的房子外面挂上两条横幅。一个说

I was added from MyProgram.Main().

还有一个说

I was added from SomeObject.DoSomething()

有道理吗?

现在,在您的第二个示例中,它有点棘手。

var myString = "I was set in MyProgram.Main()";
var myObject = new SomeObject();
myObject.MyString = myString;
myObject.DoSomething();

您首先创建一个新的 string其值为"I was set in MyProgram.Main()"并将对该字符串的引用分配给 myString .然后将对同一字符串的引用分配给 myObject.MyString .同样,myStringmyObject.MyString指的是相同的 string其值为"I was set in MyProgram.Main()" .但是然后你调用 myObject.DoSomething有这条有趣的线

this.MyString = "I was set in SomeObject.DoSomething().";

好了,现在您已经创建了一个新的 string其值为"I was set in SomeObject.DoSomething()."并分配一个引用 stringmyObject.MyString .请注意,您从未更改过 myString 的引用持有。所以现在,myStringmyObject.MyString指的是不同的字符串!

我们再打个比方。我有一张纸,上面有网址。我复印那张纸给你。我们都有一张纸,上面有相同的网址。您划掉该网址并写下一个不同的地址。它不会影响我在纸上看到的内容!

最后,这个线程中的很多人都在提示 string 的不变性。 .这里发生的事情与 string 的不变性无关。 .

关于C# 奇怪的对象行为,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/7560861/

相关文章:

c# - 避免跨线程操作错误的最简洁和正确的方法?

c# - 序列包含多个元素?

.net - 添加迁移给出文件名已经存在

c++ - 为什么 Friend 函数不能访问类的私有(private)成员

java - Random 和 RandomGenerator 的区别

c# - 工具提示文化是错误的

c# - 是否有可能在运行过程中出现 "talk"?

.net - 将数组传递给函数

c# - WCF 消息 :How to remove the SOAP Header element?

c# - 缺少 System.Windows.Freezable