引用变量,而不是对象

本文关键字:对象 变量 引用 | 更新日期: 2023-09-27 17:56:15

我希望我可以做一个引用,该引用将始终指向该特定变量,而不是指向该变量当前表示的对象(或更准确地说是内存位置)。

例如,假设我有以下程序,我想创建一个对 MyClass a 的引用,以便它始终返回 MyClass a 中的任何值,即使该值发生变化。我有一些看起来像的代码。

class MyClass
{
    public int value = 0;
}
class Program
{
    static MyClass saved; //maintained and used by the following two functions
    static void StoreReference(MyClass input)
    {
        saved = input;
    }
    static void SetValue()
    {
        saved.value = 42;
    }
    static void Main(string[] args)
    {
        //A couple arbitrary classes I'd like to have references to
        MyClass a = new MyClass();
        MyClass b = new MyClass();
        StoreReference(a);
        a = b;
        SetValue();
        Console.Write(a.value); //should print 42, instead prints 0 since it reads in the original object a was set to
    }
}

是否有任何可以在 C# 中执行此操作,或者是否有任何可以阻止变量分配给新内存位置的东西(以便上面的代码将在 a = b 处返回错误)?

引用变量,而不是对象

您可以检查saved是否已经具有值:

static void StoreReference(MyClass input)
{
    if (saved != null) {
        return;
    }
    saved = input;
}

我在这里看到很多建议使用readonly字段或ref参数的响应,但我不确定我是否完全理解为什么这些是相关的。因此,如果我不明白您的问题,请原谅我。

但从我所看到的,你想否定赋值的效果(a = b;),这是不可能的。

唯一的选择是在调用Console.Write时切换到使用 saved 而不是a

static void Main(string[] args)
{
    MyClass a = new MyClass();
    MyClass b = new MyClass();
    StoreReference(a);
    a = b;
    SetValue();
    Console.Write(saved.value);
}

这将起作用,它将像您想要的那样打印 42。但我明白这不是你要找的。

但是,没有任何语言功能可以让代码编译让您做您想做的事情。这是一件好事。这就是编译器运行这些检查(或部分检查)的原因。如果你忘记了你有一个虚构的修饰符来使局部变量只读,并且你写出了赋值,期望它像任何C语言中的其他地方一样工作,那将是非常令人困惑的。

现在,关于其他人一直在说的话,我真的不确定我明白为什么ref会出现,但是readonly:这是一个完全合理的修饰符,可以放在你的领域,但它

  1. 仅适用于字段,这意味着它将保护saved但不能保护局部变量。
  2. 仅允许在构造函数中设置值,这不是您在此处尝试设置值的位置。

因此,如果您确实打算使用它,并且不要误会我的意思,它对它的作用非常有用,请警惕这两个事实。您需要重新构建一些架构。老实说,无论如何,我都会在static void Main(...)中避免这种情况 - 那里的构造函数废话可能会令人困惑。

无论如何,我认为您可能正在尝试解决一个本来就不应该存在的问题。看到一个真实的用例可能会有所帮助,但从你给我们的信息来看,这听起来不像是可能的,不幸的是,这是有充分理由的。


值得一提的是,您的标题和开头段落让我认为您正在寻找指向指针的指针,这在托管 C# 中是不允许的。我从未涉足过非托管 C#,但它在C++中是允许的,所以我怀疑它可能在那里得到支持。无论如何,你问题的其余部分并没有真正提醒我这一点,所以这可能无关紧要。