代码之家  ›  专栏  ›  技术社区  ›  fletcher

引用和值类型场景

  •  4
  • fletcher  · 技术社区  · 14 年前

    我一直在尝试彻底理解引用和值类型。就在我以为我有它的时候,我遇到了这个场景。。。

    class Container
    {
        public object A {get; set;}
    }
    

    当我创建这个容器类(a)的实例时,我正在创建一个引用类型的实例。我给类中的对象赋值一个整数。据我所知,这将作为一个对象,另一个引用类型装箱。

    int start = 1;  
    Container a = new Container{ A=start };
    

    我创建了容器类(b)的另一个实例,但是将第一个容器的值赋给它,b的值现在是对a的引用。

    Container b = a;
    

    当我打印出a.a和b.a的值时,它们是一样的。

    Console.WriteLine("a.A={0},b.A={1}",a.A,b.A);
    //a.A=1,b.A=1
    

    而且,正如预期的那样,当我改变a.a的值时,b.a的值也会改变,因为它们引用了相同的对象。

    a.A = 2;
    
    Console.WriteLine("a.A={0},b.A={1}",a.A,b.A);
    // a.A=2,b.A=2
    

    现在我决定尝试使用单独的本地对象。同样,我将整数放入第一个对象,并将第一个对象的值赋给第二个对象。我相信这个对象,在这一点上,应该是一个引用类型,所以c和d应该引用同一个对象。在不改变任何内容的情况下,它们返回相同的值。

    int start = 1;
    object c = start;
    object d = c;
    
    Console.WriteLine("c={0},d={1}",c,d);
    // c=1,d=1
    

    像以前一样,更改初始对象的值时,我希望两个对象的值相同。

    c = 2;
    
    Console.WriteLine("c={0},d={1}",c,d);
    // c=2,d=1
    

    当我打印这两个对象的结果时,d的值不会像以前那样改变。

    4 回复  |  直到 14 年前
        1
  •  10
  •   Jon Skeet    14 年前

    Container b = a;
    

    创建另一个 实例 . 这是另一个 变量

    下一步:

    int start = 1;
    object c = start;
    object d = c;
    Console.WriteLine("c={0},d={1}",c,d); // c=1,d=1
    

    期望两个对象的值相同。

    c = 2;
    Console.WriteLine("c={0},d={1}",c,d); // c=2,d=1
    

    这并不能改变一个事实 对象 它改变了一个世界 . 每个赋值都复制一个值—除了其中一个还执行装箱操作。让我们稍微简化一下:

    object c = "first string";
    object d = c;
    

    两者 变量

    c = "different string";
    

    这改变了世界 的价值 c c d 更改的值 不会改变 d


    现在,让我们回到之前的场景,看看为什么会有所不同。在那里,你有:

    a.A = 2;
    

    这并没有改变 a

    让我们用一个真实世界的类比来简化这个过程。假设我们所有的变量都是写有住址的纸片。变化 a.A = 2; 就像改变世界一样 在那个地址的房子。当然还有其他写着同样地址的人 他们的

    现在想想你的 / 脚本。同样,假设我们有两张纸,由于赋值运算符的缘故,它们上面都写着相同的地址。现在将新值赋值给 c c 一张纸,上面写着不同的地址。但这并不能改变事实 一张纸——上面还有旧地址,如果你去那所房子,你会发现什么都没变。它是 只有写在纸上的改变了 .

        2
  •  3
  •   Guffa    14 年前

    区别在于封装对象 Container

    在第一种情况下,您有一个包含引用的对象。当你说你创建了一个 同学们,你们没有。您刚刚复制了对现有对象的引用。由于对同一对象有两个引用,因此可以通过一个引用更改对象的内容,并通过另一个引用读取。

     a     b          a     b
      \   /            \   /
       \ /              \ /
    ---------        ---------
    |       |        |       |
    |   A   |        |   A   |
    |   |   |        |   |   |
    ----|----   ->   ----|----
        |                |
    ---------        ---------
    |       |        |       |
    |   1   |        |   2   |
    |       |        |       |
    ---------        ---------
    

    在第二种情况下,您也有两个引用两个相同的对象,但在这种情况下,您直接引用装箱对象,而不是容器。将新值指定给其中一个引用时,会得到两个单独的对象。一个对象是装箱1,另一个对象是装箱2。将新值赋给b时,它不会将值放在它所指向的框中,而是创建一个包含新值的新框对象。

     a     b             a          b
      \   /              |          |
       \ /               |          |
    ---------   ->   ---------  ---------
    |       |        |       |  |       |
    |   1   |        |   1   |  |   2   |
    |       |        |       |  |       |
    ---------        ---------  ---------
    
        3
  •  2
  •   Mark Byers    14 年前

    第一个例子是:

     a      b  
      \    /  
       \  /  
       |  |  
       v  v  
    (Container)
    

    这里只有一个容器实例。两个变量都有对此容器的引用。当你改变容器时,两个变量都会看到变化。

    object c = 1;
    object d = c;
    

    c d 指向同一个对象。

    c = 2;
    

    现在你重新分配 c 一个新的装箱整数 c 正在指向两个不同的对象。这两个物体没有任何联系。

     Before                 After
    
     c      d               c                    d
      \    /         c=2    |                    |
       \  /          ---->  |                    |
       |  |                 |                    |
       v  v                 v                    v
    (boxed integer 1)      (boxed integer 2)    (boxed integer 1)
    
        4
  •  0
  •   Matthew Manela    14 年前

    在你的第二种情况下,你正在做一些完全不同的事情。当你这么做的时候:

    c = 2
    

    你实际上创建了一个全新的对象。int的值类型被转换为一个对象,因此创建了一个新的引用对象。此时,“d”变量不再引用与“c”变量相同的对象。