值和引用类型混淆

Value and Reference types confusion

我访问了有关此主题的每个网站,并且在过去几天阅读了 Jon Skeets 关于 References and Values and Parameter passing 的文章。我理解了这两种类型的概念,它们代表什么以及值和引用参数的区别是什么是另一个规范。

我了解它的工作原理以及您可以如何使用它,但我不明白大家对这个话题的看法。你们都在那里说,例如 int 是一个值类型, string 是一个引用类型。但根据我的理解,类型基本上只取决于它们声明的 class 类型。

查看此代码片段以了解我的意思:

public struct IntHolder
{
   public int number;
}

IntHolder first = new IntHolder();
first.number = 5;
IntHolder second = first;
first.number = 6;

现在 second.number 的值为 5。如果将 struct 更改为 classnumber 将充当引用类型,因此完全没有关系int 是一般的值类型,它只是 class 的类型。同样的例子也适用于 string,等等......

显然,声明对象的 class 的类型设置了其对象的类型,或者我误解了一个核心概念。请纠正我并帮助我理解它的正确性,或者告诉我说 int string 等背后的意义是什么......有一个特殊的类型,即使它们何时初始化并不重要,所以基本上总是。

这与您要更改的字段类型无关。这里相关的确实只是父类型的种类:

IntHolder first = new IntHolder();
IntHolder second = first;

根据 IntHolder 的种类,这有两种不同的效果:

对于值类型 (struct),这会创建一个 copy。值类型对象的数据对象同存,所以全部复制。这有点等同于:

IntHolder second = new IntHolder();
second.number = first.number;
// and all other fields (visible or not) are copied too

这意味着对 copied 值类型的字段的赋值将覆盖该值而不影响原始对象。这就像局部变量的行为方式:

var x = 5;
var y = 2;
y = 3; // this does not change x

然而,当类型是引用类型时,赋值second = first只是复制引用。保留值的基础对象对于两者都是相同的。因此,对任何一个对象的更改都会影响另一个对象——因为没有 “其他”:它是同一个对象,只是被两个单独的变量引用。


回答评论中的后续问题:

How do I need to imagine it that an int variable is a value type and string is a reference type? I mean, so the int variable directly contains the number and the string variable is just like a pointer to a storage location of the string object?

是的,就是这样。引用的值基本上只是指向对象实际所在内存的指针,而值类型的值是整个对象本身。

这就是为什么将值类型作为方法的参数意味着当调用该方法时,将整个值类型对象复制到堆栈中以执行该方法。

一个类型是值类型并不意味着它的成员也都是值类型。例如,值类型内部的字符串成员实际存储的值仍然是对字符串对象的引用。同样,引用类型的实际内存将包含值类型的实际值,以及对引用类型的 other 内存位置的引用。

If the parent type always matter more than the objects types, what can I use the type of int and string for?

没有什么比另一个更重要。作为值或引用类型的对象仅影响该对象的存储方式。对于对象的成员,这是完全单独评估的。

Is it possible if you just have one class and a bunch of variables to set some of them just as a reference to another variable, for example int variables.

您不能像在 C 中那样拥有值类型的引用指针,不。但是您可以引用字段,这些字段允许您改变值类型字段的值。例如:

class Test
{
    private int field;

    public void ShowExample()
    {
        // set the value
        field = 12;

        // call the method and pass *a reference* to the field
        // note the special syntax
        MutateField(ref field);

        // the field, which is a value type, was mutated because it was passed as a reference
        Console.WriteLine(field == 4);
    }

    private static void MutateField(ref int value)
    {
        value = 4;
    }
}