价值和参考类型混淆

时间:2017-08-09 11:47:03

标签: c# value-type reference-type

我在每个网站上都有关于这个主题的内容,过去几天通过Jon Skeets关于References and ValuesParameter passing的文章阅读。我理解这两种类型的概念,它们代表什么以及与Value和Reference参数的区别是什么是另一种规范。

我理解这是如何工作的,以及如何使用它,但我不明白有人在谈论这个话题。大家都说,例如int是值类型,string是引用类型。但根据我的理解,类型基本上只取决于它们被宣告的类的类型。

看看这段代码片段,了解我的意思:

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无关紧要string 1}}在generell中是一个值类型,它只是类的类型。同样的例子适用于int等......

显然,声明对象的类的类型设置了对象的类型,或者我错过了一个核心概念。请纠正我并帮助我理解它是正确的,或者告诉string {{1}}等等有什么特别的意思,即使它们初始化时无关紧要,所以基本上总是如此。

1 个答案:

答案 0 :(得分:8)

这与您要更改的字段类型无关。这里的相关内容实际上只是父类型的类型:

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

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

对于值类型(struct),这会创建副本。值类型对象的数据与对象一起生成,因此所有这些都被复制。它有点像这样:

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

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

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

但是,当类型是引用类型时,作业second = first只会复制引用。保存值的基础对象对于两者都是相同的。因此,对任一对象的更改都会影响另一个 - 因为没有“other”:它是由两个单独的变量引用的相同对象。

回答评论中的后续问题:

  

我如何想象int变量是值类型而string是引用类型?我的意思是,int变量直接包含数字,string变量就像指向字符串对象存储位置的指针一样?

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

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

作为值类型的类型并不意味着它的成员也都是值类型。例如,值类型中的字符串成员的实际存储值仍然是对字符串对象的引用。类似地,引用类型的实际内存将包含值类型的实际值,以及对引用类型的其他内存位置的引用。

  

如果父类型总是比对象类型更重要,我可以使用int和string的类型吗?

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

  

是否有可能只有一个类和一堆变量来设置其中一些变量作为对另一个变量的引用,例如int变量。

您不能拥有值类型的引用指针,就像您在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;
    }
}