【问题标题】:Pass by reference vs Pass by assignment? C# vs Python通过引用传递与通过分配传递? C# 与 Python
【发布时间】:2020-12-06 13:44:09
【问题描述】:

我同时使用 C# 和 Python。

就在内存中创建的内容而言,在 C# 中传递引用类型和在 Python 中传递(通过赋值)之间有区别吗?似乎在任何一种情况下,如果变量在函数中被更改*,它也会在外部范围内被更改。

(*) 当然在 Python 中它必须是可变的才能发生。不可变对象无法更改 - 但这是另一个主题。

我们基本上只是在为同一个过程讨论不同的术语,还是在内存中的底层机制方面存在概念上的差异?

【问题讨论】:

    标签: python c# reference variable-assignment


    【解决方案1】:

    首先,在 C# 中,默认情况下所有参数都按值传递。这与类型是引用类型还是值类型无关,两者的行为方式完全相同。

    现在,问题是,什么是变量? 变量的占位符,仅此而已。当通过副本传递变量时,副本被制作。

    存储在变量中的值是什么?好吧,如果变量的类型是引用类型,那么值基本上就是它所引用的对象的内存地址。如果是值类型,那么值就是对象本身。

    所以当你说:

    似乎在任何一种情况下,如果变量在函数中被更改*,它也会在外部范围内被更改。

    这是非常错误的,因为在我看来,您似乎将参数的类型与其传递方式混为一谈:

    第一个例子:

    var a = new object();
    Foo(a);
    var isNull = ReferenceEquals(a, null); //false!
    
    void Foo(object o) { o = null; }
    

    这里,一个引用类型变量a通过值传递,复制一个然后在Foo内部重新分配给nulla 不在乎 copyFoo 内被重新签名,它仍然会指向同一个对象。

    如果你通过引用传递参数,事情当然会改变:

    var a = new object();
    Foo(ref a);
    var isNull = ReferenceEquals(a, null); //true!
    
    void Foo(ref object o) { o = null; }
    

    现在您不是在复制名为 oa,而是通过名为 o 的别名传递 a 本身。

    值类型的行为完全相同:

    var a = 1;
    Foo(a);
    var isNull = 1 == 0; //false!
    
    void Foo(int i) { i = 0; }
    

    var a = 1;
    Foo(ref a);
    var isNull = 1 == 0; //true!
    
    void Foo(ref int i) { i = 0; }
    

    值类型和引用类型之间的差异,当你通过值传递它时,是由于变量的值是什么。正如我们之前所说,引用类型变量存储地址,因此即使您传递一个副本,该副本也指向同一个对象,因此对象的任何更改都可以从两个变量中看到:

    var ii = new List<int>();
    Foo(ii);
    var b = ii.Count == 1; //true!
    
    void Foo(List<int> list) { list.Add(1); } 
    

    但是对于值类型,值就是对象本身,因此您传递对象的副本,因此您正在修改副本

    struct MutableStruct
    {
        public int I { get; set; }
    }
    
    var m = new mutableStruct();
    Foo(m);
    var b = m.I == 1; //false!
    
    void Foo(MutableStruct mutableStruct) { mutableStruct.I = 1; } 
    

    这会让事情更清楚吗?

    【讨论】:

    • 这非常有帮助,非常感谢。我仍在吸收它并在我的计算机上尝试您的示例。
    猜你喜欢
    • 1970-01-01
    • 2013-04-21
    • 2011-08-21
    • 1970-01-01
    • 2018-09-01
    • 2012-04-14
    • 1970-01-01
    • 1970-01-01
    • 2020-04-01
    相关资源
    最近更新 更多