理解c#中的引用行为

本文关键字:引用 理解 | 更新日期: 2023-09-27 18:16:13

我有一个关于以下代码的问题:

    static void Main(string[] args)
    {
        var msg = new Message()
        {
            Description = new Description() { Key = 1, Value = "Foo"},
            ID = 1,
            Name = "MyMessage"
        };
        changeDescription(msg.Description);
    }
    static void changeDescription(Description descrToChange)
    {
        descrToChange = new Description() { Key = 2, Value = "Foobar" };
    }

为什么我的msg在方法调用后有Description (Key = 1, Value = "Foo") ?

类:

class Message
{
    public Description Description { get; set; }
    public int ID { get; set; }
    public string Name { get; set; }
}
class Description
{
    public int Key { get; set; }
    public string Value { get; set; }
}

提前谢谢你

编辑:如果我使用'ref'关键字作为你的一些建议,我得到这个错误:

Error   CS0206  A property or indexer may not be passed as an out or ref parameter

理解c#中的引用行为

在您的方法中,您创建了一个全新的Description实例。对该实例的引用存储在本地变量descrToChange中。

descrToChange作为参数,是引用变量msg.Description的副本。descrToChange内部的原始引用在您的方法中被覆盖,msg.Description内部的引用保持不变。

*方案#1:使用已经创建的实例*

一个解决方案是修改引用变量已经指向的实例的成员。您不需要在方法中创建新实例,而只需使用已经存在的实例:

static void changeDescription(Description descrToChange)
{
    descrToChange.Key = 2;
    descrToChange.Value = "Foobar";
}

*解决方案#2:使用父节点来修改它的子节点*

另一个解决方案是使用Message作为参数:

static void changeDescription(Message msg)
{
    msg.Description = new Description() { Key = 2, Value = "Foobar" };
}

,并像这样命名:

changeDescription(msg);

*解决方案#3:使用ref修改引用(在变量内)*

如果msg.Description是一个字段而不是一个属性,并且您想通过方法修改msg.Description中的引用,则使用ref。注意:明智地使用这个关键字:

static void changeDescription(ref Description descrToChange)
{
    descrToChange = new Description() { Key = 2, Value = "Foobar" };
}

,并使用:

changeDescription(ref msg.Description);

这只能在你的属性是一个字段的情况下工作,我不建议这样做:

class Message
{
    public Description Description;
    public int ID { get; set; }
    public string Name { get; set; }
}

为什么我的msg后面有Description (Key = 1, Value = "Foo")方法调用吗?

因为你没有使用ref关键字。

static void changeDescription(ref Description descrToChange)
{
    descrToChange = new Description() { Key = 2, Value = "Foobar" };
}

你也必须改变你的方法调用如下:

 changeDescription(ref msg.Description);

ref关键字导致参数通过引用传递,而不是通过价值。通过引用传递的效果是,对参数在被调用方法中反映在调用方法中。为例如,如果调用者传递一个局部变量表达式或数组元素访问表达式,被调用的方法替换对象ref形参引用的对象,然后是调用者的局部变量或数组元素现在指向新对象。

有关ref关键字的更多信息,请查看此处。

现在让我们进一步了解它:

descrToChange = new Description() { Key = 2, Value = "Foobar" };

在上面的代码行中,我们创建了一个新的Description对象并将其赋值给descrToChange。但是,这个变量descrToChange作为参数传递给方法,并且可以保存Description类型对象的引用。我们可以传递一个Description类型的对象给方法,然后改变它的数据,但是我们不能改变对这个对象的引用。如果这是您的意图,那么您应该通过引用传递参数。

您覆盖了引用。您可以更改现有的对象。

static void changeDescription(Description descrToChange)
{
    descrToChange.Key = 2;
    descrToChange.Value = "Foobar";
}