字符串是引用类型,因此如果我在结构中使用它们,则引用将存储在堆栈中。但为什么这段代码给我的 foo1.Bar 与 foo2.Bar 不同?
var foo1 = new Foo();
foo1.Bar = "test";
var foo2 = foo1;
foo2.Bar = "test2";
Console.WriteLine($"foo1 -> {foo1.Bar}");
Console.WriteLine($"foo2 -> {foo2.Bar}");
struct Foo
{
public string Bar;
}
Run Code Online (Sandbox Code Playgroud)
foo1.Bar 和 foo2.Bar 不应该存储相同的引用,并且在这种情况下最后显示相同的结果吗?
我正在使用 .NET 6、C# 10.0
让我们一次完成前四行:
\nvar foo1 = new Foo();\nRun Code Online (Sandbox Code Playgroud)\n上面创建了一个Foo完全包含在变量中的新实例foo1,无论 foo1 可能出现在哪里(我们通常从堆栈的角度思考,但也有例外)。
foo1.Bar = "test";\nRun Code Online (Sandbox Code Playgroud)\n现在在堆内存中创建了一个字符串对象,并将引用分配给变量Bar的属性foo1。C# 编译器对字符串进行了一些特殊处理,因此它们具有一些值类型语义(即:您不必编写foo1.Bar = new string("test");),但它们实际上是引用类型,因此只有引用被分配给foo1.Bar。
var foo2 = foo1;\nRun Code Online (Sandbox Code Playgroud)\n这会将Foo实例复制foo1到新foo2变量中。因为这是一个结构体,而不是一个类,所以 的内容foo1被复制到完全包含在 中的新对象中foo2,并且可能仍在堆栈上。如果Foo类型是类而不是结构,则foo2只会收到对相同对象的引用foo1,但实际上这两个变量现在是完全不同的对象。参考.Bar也被复制作为其中的一部分,但只是参考。因此,您现在有两个不同的引用引用同一“测试”字符串对象。
foo2.Bar = "test2";\nRun Code Online (Sandbox Code Playgroud)\n在堆内存中创建一个新的“test2”字符串对象,并分配给该foo2.Bar属性的引用。这取代了旧的参考。但是,此引用与 \xe2\x80\x94 不同foo1.Bar,它们以前引用相同的对象,而是不同的引用 \xe2\x80\x94,因此foo1未更改。同样,如果Foo是一个类而不是一个结构,那么此时的foo1和变量将保存同一对象的引用值,在这种情况下更新也会更新,但作为一个结构,我们最终得到的是副本,并且副本可以自由发散。foo2foo2.Barfoo1.Bar
该领域的一些补充阅读:
\n\n\n/sf/answers/3669962971/
\n
\n https://learn.microsoft.com/en-us/archive/blogs/ericlippert/the-truth-about-value-types
| 归档时间: |
|
| 查看次数: |
726 次 |
| 最近记录: |