簡體   English   中英

通過引用傳遞與通過分配傳遞? C# 與 Python

[英]Pass by reference vs Pass by assignment? C# vs Python

我同時在 C# 和 Python 工作。

就 memory 中創建的內容而言,在 C# 中傳遞引用類型和在 Python 中傳遞(通過賦值)之間是否有區別? 似乎在任何一種情況下,如果變量在 function 中更改*,它也會在外部 scope 中更改。

(*) 當然在 Python 中它必須是可變的才能發生。 不可更改的 object 無法更改 - 但這是另一個主題。

就 memory 中的底層機制而言,我們基本上只是在談論同一個過程的不同術語,還是在這里需要學習概念上的差異?

首先,arguments在C#中默認都是傳值的。 這與類型是引用類型或值類型無關,兩者的行為方式完全相同。

現在,問題是,什么是變量? 變量的占位符,僅此而已。 當通過副本傳遞變量時,會生成該副本

存儲在變量中的值是什么? 那么,如果變量的類型是引用類型,那么值基本上就是它引用的object的memory地址。 如果它是一個值類型,那么這個值就是對象本身。

所以當你說:

似乎在任何一種情況下,如果變量在 function 中更改*,它也會在外部 scope 中更改。

這是非常錯誤的,因為在我看來,您似乎將論點的類型與它的傳遞方式混為一談:

第一個例子:

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

void Foo(object o) { o = null; }

在這里,一個引用類型的變量a按值傳遞,制作一個副本,然后在Foo內部將其重新分配給null a不在乎副本Foo中重新分配,它仍將指向相同的 object。

如果您通過引用傳遞參數,事情當然會改變:

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

void Foo(ref object o) { o = null; }

現在你不是在復制a名為o的副本,而是在傳遞a名為o的別名。

值類型的行為完全相同:

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; }

當您通過值傳遞 long 時,值類型和引用類型之間的區別在於變量的值是什么。 就像我們之前說的,引用類型變量存儲地址,所以即使你傳遞一個副本,副本指向同一個 object,所以 object 中的任何更改都可以從兩個變量中看到:

var ii = new List<int>();
Foo(ii);
var b = ii.Count == 1; //true!

void Foo(List<int> list) { list.Add(1); } 

但是對於值類型,值是 object 本身,因此您傳遞的是 object 的副本,因此您正在修改副本

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; } 

這會讓事情變得更清楚嗎?

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM