Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/.net/25.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C# 参考和值类型场景_C#_.net_Value Type_Reference Type - Fatal编程技术网

C# 参考和值类型场景

C# 参考和值类型场景,c#,.net,value-type,reference-type,C#,.net,Value Type,Reference Type,我一直在尝试彻底理解引用和值类型。就在我以为我有它的时候,我遇到了这个场景 我创建了一个包含单个对象的类 class Container { public object A {get; set;} } 当我创建此容器类(a)的实例时,我正在创建引用类型的实例。我为类中的对象指定了一个整数。据我所知,这将作为一个对象装箱,另一个引用类型 int start = 1; Container a = new Container{ A=start }; 我创建了容器类(b)的另一个实例,但

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

我创建了一个包含单个对象的类

class Container
{
    public object A {get; set;}
}
当我创建此容器类(a)的实例时,我正在创建引用类型的实例。我为类中的对象指定了一个整数。据我所知,这将作为一个对象装箱,另一个引用类型

int start = 1;  
Container a = new Container{ A=start };
我创建了容器类(b)的另一个实例,但将第一个容器的值分配给它,b的值现在是对a的引用

Container 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
c = 2;

Console.WriteLine("c={0},d={1}",c,d);
// c=2,d=1
c = 2;
Console.WriteLine("c={0},d={1}",c,d); // c=2,d=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 = 2;
现在我决定尝试使用单独的局部对象。同样,我将整数框入第一个对象,并将第一个对象的值指定给第二个对象。我相信这个对象,在这一点上,应该是一个引用类型,所以c和d应该引用同一个对象。在不更改任何内容的情况下,它们返回相同的值

int start = 1;
object c = start;
object d = c;

Console.WriteLine("c={0},d={1}",c,d);
// c=1,d=1
与前面一样,在更改初始对象的值时,我希望两个对象的值相同

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

Console.WriteLine("c={0},d={1}",c,d);
// c=2,d=1
c = 2;
Console.WriteLine("c={0},d={1}",c,d); // c=2,d=1
当我打印这两个对象的结果时,d的值不会像以前那样改变

有人能解释一下为什么这个场景中的任务与前一个场景不同吗


谢谢

这是您的第一个错误:

我创建了容器类(b)的另一个实例,但分配了第一个实例的值 容器中,b的值现在是对a的引用

Container b = a;
Container b = a;
这不是在创建另一个实例。它正在声明另一个变量。现在两个变量都引用同一个对象

a.A = 2;

Console.WriteLine("a.A={0},b.A={1}",a.A,b.A);
// a.A=2,b.A=2
c = 2;
(我将在继续阅读的同时继续编辑此答案…)

下一步:

与前面一样,在更改初始对象的值时 期望两个对象的值相同

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

Console.WriteLine("c={0},d={1}",c,d);
// c=2,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
的值,它们将分别是“不同的字符串”和“第一个字符串”更改
c
的值不会更改
d
的值


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

a.A = 2;
这根本不会改变
a
的值。它正在更改
a
引用的对象中的数据

让我们用一个真实世界的类比来简化这个过程。假设我们所有的变量都是写有住址的纸片。
a.a=2的变化就像在那个地址更改房子的内容一样。当然,其他任何人只要在他们的纸上写上相同的地址,就会看到变化

现在想想你的
c
/
d
场景。再一次,假设我们有两张纸,由于赋值运算符,它们上面都写着相同的地址。现在,为
c
变量本身指定一个新值就像擦掉
c
一张纸上的地址,然后在上面写一个不同的地址。这根本不会改变
d
这张纸——它仍然保留着旧地址,如果你去那所房子,你会发现什么都没有改变。只是写在纸上的东西变了


这有帮助吗?

在第一个示例中,您有:

 a      b  
  \    /  
   \  /  
   |  |  
   v  v  
(Container)
这里只有一个容器实例。这两个变量都引用了此容器。当您改变容器时,两个变量都会看到变化

但是,在本规范中:

object c = 1;
object d = c;
第二个赋值并不意味着“d是c的别名”,它只是意味着在第二个赋值
c
d
之后指向同一个对象

a.A = 2;

Console.WriteLine("a.A={0},b.A={1}",a.A,b.A);
// a.A=2,b.A=2
c = 2;
现在您将
c
重新指定给一个新的装箱整数,这样
c
d
现在指向两个不同的对象。这两个对象没有任何关联

 Before                 After

 c      d               c                    d
  \    /         c=2    |                    |
   \  /          ---->  |                    |
   |  |                 |                    |
   v  v                 v                    v
(boxed integer 1)      (boxed integer 2)    (boxed integer 1)

在第一个场景中,您对堆上的一个对象进行了引用。有两个变量(“a”,“b”)指向同一个对象。这就是为什么当您更改此对象的一个成员时,您会看到它在两个变量上都得到反映

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

c = 2

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

不同之处在于封装对象
容器

在第一种情况下,您有一个包含引用的对象。当您说您创建了
容器
类的新实例时,您没有这样做。您刚刚将引用复制到现有对象。由于对同一对象有两个引用,因此可以通过一个引用更改该对象的内容,并通过另一个引用读取该对象

 a     b          a     b
  \   /            \   /
   \ /              \ /
---------        ---------
|       |        |       |
|   A   |        |   A   |
|   |   |        |   |   |
----|----   ->   ----|----
    |                |
---------        ---------
|       |        |       |
|   1   |        |   2   |
|       |        |       |
---------        ---------
在第二种情况下,也有两个引用两个相同的对象,但在这种情况下,直接引用装箱对象,而不是容器。将新值指定给其中一个参照时,将得到两个单独的对象。一个对象是装箱1,另一个对象是装箱2。当你给b分配一个新的值时,它不会把这个值放在th中