【问题标题】:Why does assignment to parameter not change object?为什么分配给参数不会改变对象?
【发布时间】:2014-05-10 19:49:53
【问题描述】:
classes deal with the reference types and traditional data types deal with the value type just for example :
int i=5;
int j=i;
i=3 ; //then this will output i=3 and j=5 because they are in the different memory blocks .

类似地,如果我们谈论一个类的对象,比如点类

class point
{
    public int x,y;
    void somefucnt(point p,int x)
    {
        Console.writeline("value of x is "+p.x);
        x=22;
        Console.writeline("value of x is "+p.x);
    }
}
class someotherclass
{
    static void Main(string [] args )
    {
        p1.x=10;
        p1.somefunct(p1,p1.x); 
    }
}

尽管我将 x 更改为其他值,但两个 console.write 语句都打印 10 ?为什么会这样?因为 p 只是对 x 的引用,所以它应该通过改变 x 的值来更新。这件事真的让我很困惑。

【问题讨论】:

    标签: c# .net


    【解决方案1】:

    观察到的行为与值类型与引用类型无关 - 它与调用方法时的Evaluation of Strategy(或“调用约定”)有关。

    没有ref/out,C#总是Call by Value1,这意味着重新分配参数不会影响调用者绑定 .因此,对x 参数 的重新分配与参数值(或此类值的来源)无关——它是值类型还是引用类型都没有关系。

    Reference type still needs pass by ref?(为什么调用者看不到参数重新分配):

    在 C# 中,一切都是按值传递的。但是,当您传递引用类型时,引用本身是按值传递的,即传递原始引用的副本。因此,您可以更改引用副本指向的对象的状态,但是 如果您为引用 [参数] 分配一个新值,您只会更改 [局部变量] 副本指向的内容,而不是原始引用[在参数表达式中]。

    还有Passing reference type in C#(关于为什么不需要ref 来改变引用类型)

    即对象的地址是按值传递的,但是对象和对象的地址是一样的。因此,当您调用方法时,VM 会复制引用;您只是在更改副本。


    1 对于引用类型,“按值调用 [引用]”或“按 [引用] 值调用”可能有助于解决问题。 Eric Lippert 写了一篇热门文章 The Truth about Value Types,鼓励将 引用值 视为与引用(或引用类型的实例)不同的概念。

    【讨论】:

    • 感谢您提升我的知识@user2864740
    【解决方案2】:
    void somefucnt(point p,int x){
    Console.writeline("value of x is "+p.x);
    
    x=22;
    Console.writeline("value of x is "+p.x);
    
    }
    

    这里,x=22 不会改变 p.x 但参数 x(point p,int x)
    通常,您对值/引用的假设是可以的(如果我理解正确的话)。

    提示:Google for c# this 而不是将对象传递给它自己的方法

    【讨论】:

      【解决方案3】:

      您更改的是参数 (x) 的值,而不是 p.x 的值,除非您使用 ref 关键字,否则值类型是按值传递的。

      和你的第一个例子一样,ij以及参数xp1.x之间没有关系。每个变量在内存中都有自己的空间。所以改变其中一个不影响对方。

      【讨论】:

      • ref 影响变量,而不是。第一个子句对引用和值类型都适用,我发现第二个在上下文中具有误导性,因为引用类型也是按值调用(尽管总是引用值)。
      【解决方案4】:

      somefucnt 函数中有两个名为 x 的不同变量。一个是您要更改的成员变量x,另一个是void somefucnt(point p, int x) 中的函数输入参数。当你说x = 22时,输入参数x改变了,而不是成员变量x。

      如果您将x = 22 行更改为this.x = 22,那么它应该可以正常工作。

      旁注:

      避免混淆的一个好习惯是始终将类成员设为私有并将它们命名为_x。否则,在 CamelCase 中具有公共自动属性,如下所示:

      public int X { get; set; }
      

      这些方法避免了类变量和函数输入变量之间的歧义。

      【讨论】:

      • 这个答案有什么问题吗?请解释否决票。
      • 我找不到任何错误 - 我更改了顺序以将答案的重点放在前面,因为最初的感知可以起到很大的作用。
      • 你的 ans 的第二部分也可以解决这个问题,那么如果有一种情况我需要将一个类的对象(你可以说是引用)传递给继承类的方法怎么办或本身。我知道那听起来很嘈杂,但那时属性将不起作用。那你能再详细说明一下吗?
      猜你喜欢
      • 1970-01-01
      • 2021-07-31
      • 2014-08-26
      • 2021-04-18
      • 2016-08-26
      • 2020-05-07
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多