将包含类实例的结构的变量分配给另一个变量

时间:2011-06-26 22:02:19

标签: c# class struct value-type reference-type

根据我的理解,将结构的变量赋值给另一个相同类型的变量将生成一个副本。但是这条规则似乎已经打破了,如下图所示。你能解释一下为什么会这样吗?

enter image description here

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();
        }
    }
}

3 个答案:

答案 0 :(得分:4)

您在主题中回答了您的问题。

您的结构包含一个引用,当复制结构时,它被复制为一块内存,包括引用(不是引用的对象),就像引用是整数或其他原语一样。

复制结构不会导致克隆。

事实上,在结构中放置引用是一个坏主意,应该避免。 一个例外是不可变引用对象(例如字符串),它们在结构中是“安全的”,因为它们不能被修改,但是你仍然会在内存中松散局部性。

请记住,值类型本地存储在其定义范围内,引用类型始终存储在堆上,引用存储在本地定义的范围内。

答案 1 :(得分:2)

添加其他人所说的内容: 如果你需要说服自己p1.inner和p2.inner确实指向同一个类实例,你可以运行如下代码:

Console.WriteLine("ReferenceEquals:{0}", object.ReferenceEquals(p1.inner, p2.inner));

如果你在“外部p2 = p1;”之后的任何时间运行它,它将始终写入:“ReferenceEquals:True”。

答案 2 :(得分:0)

P1P2都指向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();