C#奇怪的对象行为

Che*_*hev 5 .net c# reference class object

在处理自定义对象时,我注意到了C#中的一些东西,我发现它有点奇怪.我确信这只是对我缺乏了解,所以也许有人可以启发我.

如果我创建一个自定义对象,然后我将该对象分配给另一个对象的属性,并且第二个对象修改分配给它的对象,那么这些更改将反映在执行分配的同一个类中,即使没有返回任何内容.

你想用英语吗?这是一个例子:

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()");
    }
}
Run Code Online (Sandbox Code Playgroud)

在上面的例子中我会想到,因为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().";
    }
}
Run Code Online (Sandbox Code Playgroud)

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

jas*_*son 15

这不奇怪,也不奇怪.创建类时,可以创建引用类型.当您将引用传递给周围的对象时,对引用该对象的任何人都可以看到对它们引用的对象的修改.

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

因此,在此代码块中,您实例化一个新实例,List<string>并将该实例的引用分配给该变量myList.然后添加"I was added from MyProgram.Main()."到引用的列表中myList.然后你分配一个refernce到同一份名单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().
Run Code Online (Sandbox Code Playgroud)

而另一个说

I was added from SomeObject.DoSomething()
Run Code Online (Sandbox Code Playgroud)

合理?

现在,在你的第二个例子中,它有点棘手.

var myString = "I was set in MyProgram.Main()";
var myObject = new SomeObject();
myObject.MyString = myString;
myObject.DoSomething();
Run Code Online (Sandbox Code Playgroud)

首先创建一个新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().";
Run Code Online (Sandbox Code Playgroud)

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

让我们再次类推.我有一张纸上有一个网址.我复印那张纸给你.我们都有一张纸,上面有相同的网址.您划掉该网址并写下不同的地址.它不影响我在纸上看到的东西!

最后,这个帖子中的很多人都在谈论不变性string.这里发生的事情与...的不变性无关string.