引用变量,而不是对象

Posted

技术标签:

【中文标题】引用变量,而不是对象【英文标题】:Reference To Variable, Not To Object 【发布时间】:2015-08-30 07:52:03 【问题描述】:

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

例如,假设我有以下程序,我想创建对 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 处返回错误)?

【问题讨论】:

可以定义为只读 你有没有尝试做 StoreReference(ref MyClass input) readonly 的问题是我希望能够说 a.value = 42 而不是 a = new MyClass(),因为第二个示例更改了 a 指向的内存位置。 这有 REAL 用例吗?如果你想让a不改变,你为什么坚持给它分配一个新的值? 只读变量只会阻止你写a=new MyClass(),不会阻止你写a.value=42 【参考方案1】:

我在这里看到不少回复建议使用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。但我知道这不是你要找的。​​p>

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

现在,看看其他人一直在说什么,我真的不明白为什么会出现ref,但是readonly:这是一个非常合理的修饰符,可以放在你的领域,但是它:

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

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

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


对于它的价值,您的标题和开头段落让我觉得您正在寻找指向指针的指针,这在托管 C# 中是不允许的。我从来没有冒险使用非托管 C#,但它在 C++ 中是允许的,所以我怀疑它可能在那里得到支持。无论如何,你的问题的其余部分并没有真正让我想起这一点,所以这可能不相关。

【讨论】:

【参考方案2】:

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

static void StoreReference(MyClass input)

    if (saved != null) 
        return;
    
    saved = input;

【讨论】:

以上是关于引用变量,而不是对象的主要内容,如果未能解决你的问题,请参考以下文章

javascript篇-----变量和变量的数据类型值

为什么java是只有值传递而没有引用传递

js基础之--变量 作用域和内存问题

java final 修饰变量

变量,作用域和内存的问题

对象引用 可变性 垃圾回收