对象实际上是引用类型

本文关键字:引用类型 实际上 对象 | 更新日期: 2023-09-27 18:00:47

据我所知,ClassObject是引用类型。

我有以下方法来更改值

public void ChangeValue(MyClass classobj)
{
    classobj.Number = classobj.Number*2;
}

我调用该方法将值加倍

var myClass=new MyClass();
int myNumber = 10;
myClass.Number = myNumber;
ChangeValue(myClass);

它将返回20,这很好,因为您可以将其解释为当您生成类的对象时,它将引用传递给方法,并更新引用值。

但我的问题是,为什么Object类型没有发生这种情况。换句话说,为什么当我制作对象并为其分配一些值时,就像下面的一样

 object myObject = new object();
 string sometext  = "Some object value";
 myObject = sometext;
 ChangeValue(myObject)

执行方法后不会更改值

public void ChangeValue(object objectValue)
{
    objectValue = null;
}

我知道方法的参数是值类型,但不能理解它对两个引用类型有不同的行为。

对象实际上是引用类型

您实际上在这里做两件不同的事情。ObjectMyClass实际上都是引用类型,这意味着您将对实际对象的引用传递到ChangeValue方法中。但是,您在方法内部看到的引用是调用者持有的引用的副本。它们指向同一个对象,因此当您在方法中操作对象时,方法的调用方可以看到您的更改,但对方法内部实际引用的更改只会影响方法本身。

在总结中,对象通过引用传递,但这些引用通过value来传递。

在你的方法

public void ChangeValue(object objectValue)
{
    objectValue = null;
}

您实际要做的是重新分配引用objectValue,该引用是调用方拥有的名为myObject的引用的副本。因为该方法只有一个副本,所以它根本不会影响调用方的引用。

有一种方法可以做到这一点,你必须通过引用传递引用。这总是让我头疼,但这就是ref关键字的作用。

public void ChangeValue(ref object objectValue)
{
    objectValue = null; // this is the SAME reference as the caller has, so the caller will see this change
}

然而,它也必须这样称呼:

ChangeValue(ref myObject);

因此,在调用站点上很明显,它可能会指向另一个对象。要知道这一点很重要,因为如果引用意外地指向不同的对象,您可能仍然有依赖于旧值的东西,并最终陷入可怕的混乱。

通过值将objectValue传递给ChangeValue(object objectValue),该值是一个引用。然后更改该值,但不更改myObject的值。

您必须将其作为ChangeValue(ref object objectValue)传递,才能逐个引用地实际传递引用的值。

这不是不同的行为,你在做不同的事情

这将与您的object示例完全一样:

    public void ChangeValue(MyClass classobj)
    {
        classobj = null;
    }

这将作为您的第一个示例(假设您将通过MyClass实例):

   public void ChangeValue(object objectValue)
    {
        ((MyClass)objectValue).Number *= 2;
    }

这里实际发生的是,当您分配参数(而不是参数的属性或字段)时,您只会更改该参数的值。调用代码中的原始值和变量保持不变。

同样的情况也发生在这里:

MyClass a = new MyClass();
MyClass b = a;
a = null;
// b still contains the value created in the first line

简单地说,引用变量保存实际值的指针(内存地址)。通过更改变量的值,可以使其指向不同的对象或null。但当您执行a.field=2时,这意味着您将获取a所引用的对象,并更改其field成员值。