【问题标题】:How is this function changing my readonly variable?这个函数如何改变我的只读变量?
【发布时间】:2011-12-10 17:55:01
【问题描述】:

我在 C# 中使用 jabber.net,有一个怪癖让我感到困惑,所以希望有人能解释它是如何做到的。我从 C++ 背景对 C# 还是很陌生,所以这可能是一个误解

我正在创建一个只读 JID 来保存我需要进入的房间:

private readonly JID messagingRoomJID;

public MyClass
{
   // Reads from database but for purpose of this question
   messagingRoomJID = new JID("user@myserver");
}

稍后我想加入一个让我感到困惑的房间

conferenceManager = new ConferenceManager();
conferenceManager.Stream = xmppClient;

// Before entering this room messagingRoomJID.Resource == null
theRoom = conferenceManager.GetRoom(messagingRoomJID);
// But now messagingRoomJID.Resource contains my username

但是 Resource 是如何改变的呢?该变量是只读的,但也不应该通过 const 引用传递,那么它是如何更新的呢?

看起来我可以这样做,但我不确定它是否明智:

theRoom = conferenceManager.GetRoom(new JID(messagingRoomJID));

【问题讨论】:

    标签: c# xmpp


    【解决方案1】:

    它不会改变变量的值。您的变量的值只是一个参考。该参考与以前保持一致。

    变化的是引用所指对象中的数据。 readonly 修饰符适用于您的变量 - 它没有说明对象本身的可变性。

    区分引用和对象非常重要 - 请参阅 my article on the topic 了解更多信息。

    【讨论】:

    • 哇,很多快速响应。我现在明白发生了什么。我曾认为它更像 C++ 中的 const 引用,但当然不是这种情况,我认为这是不幸的,但我相信有很多充分的理由说明这种情况。那么,在正常情况下,当您将对象传递给函数时,您不能保证它不会被他们的代码触及吗?
    • @Firedragon:你没有传递对象。您按值传递引用(假设它是引用类型,而不是 ref/out 参数)。是的,任何东西都可以改变对象,如果它是一个可变类型的话。有关参数传递的更多信息,请参阅pobox.com/~skeet/csharp/parameters.html。基本上,不要假设 C# 就像 C++ - 它不是! :)
    • 听起来可能不像,但这就是我的意思。只是不是最擅长解释自己:-) 我猜它类似于 C++,因为引用也是按值传递的,但不同之处在于没有相同的 const 正确性
    【解决方案2】:

    因为它正在更改您的 readonly 变量的 属性,而只有根元素本身是只读的。

    例如,

    private readonly int MyReadOnlyVariable;
    private readonly ComplexType MyReadOnlyComplexType;
    
    public MyClass()
    {
        MyReadOnlyVariable = 2;            //valid
        MyReadOnlyComplexType = something; //valid
    }
    
    public void NotAConstructor()
    {
        MyReadOnlyVariable = 2;                          //invalid
        MyReadOnlyComplexType = somethingElse;           //invalid
        MyReadOnlyComplexType.Something = somethingElse; //valid
    }
    

    所以,我们可以在构造函数中更改一次it;但是对于包含属性、暴露字段等的复杂类型,我们可以以后更改它们。这就是为什么(对于一个常见的例子)拥有一个 readonly 数组通常是一个坏主意,或者至少可以想象它通常不是预期的 - 因为数组的元素可以更改。

    【讨论】:

    • 实际上是对只读实例的引用,而不是实例本身,以及变量所引用的 instance 的属性,而不是变量的属性。跨度>
    【解决方案3】:

    所以,我认为 Jon Skeet 的回答是正确的。 例如,您的类变量 messagingRoomJID 是只读且是引用,因此您不能将其分配给新值,但您当然可以更改其所有属性的值,因为属性“资源”不是只读的。

    GetRoom() 方法调用不会更改内存中的 messingingRoomJID 变量引用,它只会更改其允许的属性之一的值。

    【讨论】:

    • 这很可能是对 Jon 的回答的评论! !
    • 我同意,当时我没有评论权限,我现在有了,这是我的第一条评论..感谢您的特权..!!
    【解决方案4】:

    readonly 表示对实例的引用不会改变。但是您可以更改此对象的任何字段。当传递给方法GetRoom 时,它通过引用传递。所以GetRoom 可以改变任何对象的字段。

    【讨论】:

      【解决方案5】:

      根据MSDN,只读字段可以在声明期间或使用构造函数进行初始化。

      可以在声明或构造函数中初始化只读字段。因此,只读字段可以具有不同的值,具体取决于使用的构造函数。

      但是,就像在您的代码中一样,您在初始化期间或使用构造函数时都没有更改,但属性 Resource 仍然包含该值。

      正如 Jon Skeet 所指出的,我会尝试添加,引用类型变量的值是 nullmemorry address

      所以,当你声明时:

      private readonly JID messagingRoomJID;
      

      当时messagingRoomJID 是只读的,但该内存位置的属性很少,在这种情况下,Resource 可以更改为另一个值。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2020-02-04
        • 2022-11-10
        • 1970-01-01
        • 2019-01-02
        • 2017-12-30
        • 1970-01-01
        • 1970-01-01
        • 2015-12-04
        相关资源
        最近更新 更多