根据我的理解,将结构的变量赋值给另一个相同类型的变量将生成一个副本。但是这条规则似乎已经打破了,如下图所示。你能解释一下为什么会这样吗?
using System;
namespace ReferenceInValue
{
class Inner
{
public int data;
public Inner(int data) { this.data = data; }
}
struct Outer
{
public Inner inner;
public Outer(int data) { this.inner = new Inner(data); }
}
class Program
{
static void Main(string[] args)
{
Outer p1 = new Outer(1);
Outer p2 = p1;
Console.WriteLine("p1:{0}, p2:{1}", p1.inner.data, p2.inner.data);
p1.inner.data = 2;
Console.WriteLine("p1:{0}, p2:{1}", p1.inner.data, p2.inner.data);
p2.inner.data = 3;
Console.WriteLine("p1:{0}, p2:{1}", p1.inner.data, p2.inner.data);
Console.ReadKey();
}
}
}
答案 0 :(得分:4)
您在主题中回答了您的问题。
您的结构包含一个引用,当复制结构时,它被复制为一块内存,包括引用(不是引用的对象),就像引用是整数或其他原语一样。
复制结构不会导致克隆。
事实上,在结构中放置引用是一个坏主意,应该避免。 一个例外是不可变引用对象(例如字符串),它们在结构中是“安全的”,因为它们不能被修改,但是你仍然会在内存中松散局部性。
请记住,值类型本地存储在其定义范围内,引用类型始终存储在堆上,引用存储在本地定义的范围内。
答案 1 :(得分:2)
添加其他人所说的内容: 如果你需要说服自己p1.inner和p2.inner确实指向同一个类实例,你可以运行如下代码:
Console.WriteLine("ReferenceEquals:{0}", object.ReferenceEquals(p1.inner, p2.inner));
如果你在“外部p2 = p1;”之后的任何时间运行它,它将始终写入:“ReferenceEquals:True”。
答案 2 :(得分:0)
P1
和P2
都指向Inner
类型的一个对象...
这就是价值观相同的原因......
struct Outer
{
public Inner inner;
public Outer(int data) { this.inner = new Inner(data); }
public Clone() { return new Outer(this.inner.data); }
}
现在尝试使用这样的代码:
...
p2 = p1.Clone();