为什么在c#中引用类型不更新

本文关键字:更新 引用类型 为什么 | 更新日期: 2023-09-27 18:02:32

这是我的c#代码。为什么在c#中引用类型不更新,下面是代码

 class Program
    {
        public static void Main(string[] args)
        {
            var a = A.field;
            A.field = "2";
            Console.WriteLine(a);
            Console.Read();
        }
    }
    public static class A
    {
        public static string field = "1";
    }

结果是1,为什么??

为什么在c#中引用类型不更新

public static void Main(string[] args)
{
    var a = A.field; // `a` is now a reference to the string "1"
    A.field = "2"; // `A.field` is now a reference to the string "2"
    Console.WriteLine(a); // nothing else has changed, so `a` is still a reference to the string "1"
    Console.Read();
}

所以你的问题的答案基本上是:引用不更新,因为你没有改变你写到控制台(a)的引用,而是另一个引用(A.field)。

您所看到的行为并不局限于引用类型。对于值类型也会发生同样的事情:

int x = 1;
int y = x;
x = 2; // y is still 1 at this point

这是因为y变量存储了1的值,而改变x的值并不会自动改变y的值。x不"知道"y

这与引用类型相同-在您的示例中,a在赋值后指向与A.field相同的内存位置,但它不"知道"A.field指向何处。因此改变A.field的引用不影响a

一个类比:

你给Joe一张卡片,上面写着Cat。设Ann = Joe表示安将从你那里收到一张卡片,上面写着和乔卡片上写的一样的东西。所以现在他们的卡片上都写着Cat。现在,如果你给Joe另一张卡片,上面写着, Ann的卡片上仍然写着。这个类比适用于值类型,对于引用类型,您将在卡片上写一个位置,指向可以找到单词的位置。同样的原则仍然适用。

这与以下相同:

String a = "1";
String b = a;
b = "2";
Console.Write($"a:{a} b:{b}");

最初,您有一个变量a,它引用内容为1的对象,以及一个变量b,它引用相同的对象。然后修改变量b以引用内容为2的新对象。如果修改由ab引用的对象,则使变量引用不同的对象。您必须修改b引用的对象,以便a变量"看到"更改。唉,由于String是不可变的,因此根本没有办法实际修改它。您可以使用的任何API都将导致b引用的字符串,并且a看起来与以前相同。对于可变类型,只要修改对象,而不是简单地将新对象赋值给变量,就可以看到区别:

var a = new Widget {x = 1};
var b = a;
b.x = 2;
Console.Write($"a.x: {a.x} b.x: {b.x}");

您正在分配引用而未修改原始引用。

当您将A.field赋值给a时,您将字符串"1"的引用赋值给a。之后你给A.field赋了一个新的字符串,a的原始值没有变化。它仍然保留对字符串"1"的旧引用。

如果以某种方式,您可以修改原始引用,那么您应该能够看到更改。由于您的类型是string,因此您不能真正修改它,因为它是不可变的,但是考虑一个StringBuilder的示例。

public static class A
{
    public static StringBuilder field { get; set; } = new StringBuilder("1");
}

static void Main(string[] args)
{
    var a = A.field;
    A.field.Insert(0, "2");
    Console.WriteLine(a);
    Console.Read();
}

现在您将在变量a中获得修改后的值"21"

注意,上面的代码用A.field.Insert(0, "2");修改了字段,因为变量a保存了对A.field的引用,所以在下一行可以看到更改。

但是如果你试图用这样的语句给A.field分配一个新的引用:

A.field = new StringBuilder("2");

那么A.field将有一个新的对象来引用,而之前的变量a将仍然保持旧的引用。

你可以把"reference"类型变量想象成一个方框,它是某个资源的地址。

让我们考虑一个string值。当我们将文字值string赋值给"引用"时,我们不会做以下事情:

  1. 分配一个内存区域(静态或堆)设置指定的值;
  2. 分配另一个内存区域(静态或堆)用字符串值的内存地址(引用)初始化;

当我们将一个字符串"引用"类型var赋值给另一个"引用"时,我们没有做任何事情,只是将被引用的string值的内存地址赋值给新的"引用"。

因此,如果我们用一个新的赋值语句改变了第一个"引用",第二个"引用"将不受影响,它将继续引用原始值。

最后,在c#中不可能(至少现在)有"引用到引用",你可以在c++中拥有它(指针和引用是有点不同的东西…)。参见Eric Lippert对类似问题的回答:https://stackoverflow.com/a/15328414/3762855

变量a获取静态属性A.field的值的副本。

所以当你修改A.field时,副本不会改变

try this

 class Program
    {
        static void Main(string[] args)
        {
            A.field = "2";
            var a = A.field;

            Console.WriteLine(a);
            Console.Read();
        }
    }
    public static class A
    {
        public static  string field = "1";
    }