C# 为什么引用类型没有';t用C语言更新#

C# 为什么引用类型没有';t用C语言更新#,c#,static,C#,Static,这是我的密码。为什么引用类型在C#中不更新,下面是代码 class Program { public static void Main(string[] args) { var a = A.field; A.field = "2"; Console.WriteLine(a); Console.Read(); } } publi

这是我的密码。为什么引用类型在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,为什么

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

因此,当您修改
A.field
时,副本不会更改。

试试这个

 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";
    }

因此,您的问题的答案基本上是:引用不会更新,因为您没有更改正在写入控制台的引用(
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.字段的引用不会影响
A

打个比方:


你给乔一张写有猫的卡片。让Ann=Joe
表示Ann将从您那里收到一张卡片,上面写的内容与Joe的卡片上写的内容相同。所以现在他们的卡片上都写着猫。现在如果你再给乔一张卡片,上面写着狗,安的卡片上还有猫。这个类比适用于值类型,对于引用类型,你会在卡片上写上一个位置,指向他们可以找到单词的地方。但同样的原则仍然适用。

这与以下相同:

String a = "1";
String b = a;
b = "2";
Console.Write($"a:{a} b:{b}");
最初,您有一个变量
a
,用于引用内容为
1
的对象,还有一个变量
b
,用于引用同一对象。然后修改变量
b
以引用一个新对象,该对象的内容为
2
。如果不修改
a
b
引用的对象,将变量引用为不同的对象。您必须修改
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 < /C> >。p>
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
分配给一个“引用”时,我们不做任何事情:

  • 分配一个用指定值设置的内存区域(静态或堆)
  • 分配另一个内存区域(静态或堆)用字符串值的内存地址(引用)初始化 当我们将一个字符串“reference”类型var分配给另一个“reference”时,我们不会将被引用的
    字符串的内存地址分配给新的“reference”

    因此,如果我们用新的赋值语句更改第一个“引用”,第二个将不会受到影响,它将继续引用原始值

    最后,在C语言中不可能(至少现在)有“引用引用”,你可以在C++中得到它(指针和引用是不同的东西……)。另请参见Eric Lippert对分析问题的回答:

    在分配了某个字段后,它实际上并没有引用该字段。它是一个本地变量。您已在
    A
    中保存了对字符串的引用,然后更改了
    A.field
    引用的内容
    a
    仍将是原始字符串(
    “1”
    )。@Gilad Green您没有编辑问题吗?它仍然在说“请帮我个忙”他到底能做到什么?他没有。他在问为什么会发生这种情况。这是可变和不可变对象的概念,但这个答案似乎并没有集中在OP问题上。。所以我认为提高投票率不是一个好的做法。为什么不呢?它准确地解释了OP的代码中发生了什么,以及为什么结果输出是这样。OP询问为什么通过另一个引用分配的引用在原始引用被分配另一个值时不受影响。。您的答案显示了一种避免特定si的解决方法
    A.field = new StringBuilder("2");