2010-02-24 59 views
6

將參數Value Type傳遞給c#中的函數是通過值,除非您在參數上使用ref或out關鍵字。但是這也適用於Reference TypesIList是否按價值傳遞?

具體而言,我有一個功能,需要一個IList<Foo>。傳遞給我函數的列表是否包含其包含對象副本的列表副本?或者對列表的修改是否也適用於呼叫者?如果是這樣 - 我可以通過一個聰明的方式來傳遞一份副本嗎?

public void SomeFunction() 
{ 
    IList<Foo> list = new List<Foo>(); 
    list.Add(new Foo()); 
    DoSomethingWithCopyOfTheList(list); 
    .. 
} 

public void DoSomethingWithCopyOfTheList(IList<Foo> list) 
{ 
    // Do something 
} 
+0

Thx爲快速回復的人!就像我預料的那樣。只是有一個不確定的時刻.. – stiank81 2010-02-24 09:21:47

+0

如果你想做一些聰明的事情,你可以做一個你自己的列表類,通過複製隱式投給IList。我能看到的唯一好處是,它在理論上可以防止您在傳遞集合時「忘記」複製副本。 – kyoryu 2010-02-24 09:43:32

+0

不 - 我不想那樣做。IEnumerable的List構造函數看起來像它一樣聰明。所有我需要.. – stiank81 2010-02-24 09:45:52

回答

16

所有參數是按值傳遞,除非你明確地使用refout。但是,當您傳遞引用類型的實例時,您會按值傳遞引用。即引用本身被複制,但由於它仍然指向同一個實例,所以仍然可以通過此引用修改實例。即該實例未被複制。參考是。

如果你想複製一份清單本身,List<T>有一個handy constructor,需要IEnumerable<T>

+1

此外,如果您更改函數體內的引用,則此更改在調用方中將不可見。從我+1。 – 2010-02-24 10:02:54

+1

@Aggelos:的確如此。這是通過價值傳遞的特性。 – 2010-02-24 10:17:23

3

該列表通過引用傳遞,因此如果您在SomeFunction中修改列表,則也會修改調用者的列表。

您可以通過創建一個新創建列表的副本:

var newList = new List<Foo>(oldList); 
2

您的列表通過引用傳遞。如果你想通過列表的副本,你可以這樣做:

IList<Foo> clone = new List<Foo>(list); 

如果添加/刪除克隆的元素不會改變顯示 但要素的修改自己會考慮在這兩個名單。

+0

+1的解釋:'...但這些元素本身的修改將在這兩個列表中考慮到.' – 2016-05-15 06:10:43

1

當您通過值傳遞引用類型(不帶ref或out關鍵字)時,您可以在此方法內修改此引用類型,並且所有更改都會反映給調用者的代碼。

解決你的問題,你可以明確地創建一個副本,這個副本傳遞給你的函數,或者你可以使用:

list.AsReadOnly(); 
0

當傳遞引用類型,你傳遞的參考。這是一個重要的概念。

如果傳遞參考

按地址,否則直接傳遞參考(指針)。

byval,你通過參考(指針)的副本。

引用不是引用的實例。引用與指針類似。

要傳遞引用類型實例的副本,首先必須自己創建副本並將引用傳遞給副本。因此,你將不會修改原始實例。

+2

我懷疑你可以把它放在一個更混亂的方式.. – Blindy 2010-02-24 09:23:25

+0

是更好的嗎? – MaLio 2010-02-24 09:49:03

10

你並不孤單;這讓很多人感到困惑。

以下是我喜歡的方式。

變量是一個存儲位置。

變量可以存儲某種特定類型的東西。

有兩種類型:值類型和引用類型。

引用類型變量的值是對該類型對象的引用。

值類型變量的值是該類型的對象。

形式參數是一種變量。

形式參數有三種:值參數,參考參數和輸出參數。

當您將變量用作參數值對應的參數時,該變量的值將被複制到與形式參數關聯的存儲中。如果該變量是值類型的,則創建該值的一個副本。如果變量是引用類型,則引用的副本被創建,並且這兩個變量現在引用同一個對象。無論哪種方式,都會創建一個變量值的副本。

當您使用變量作爲參數對應於out或ref參數時,該參數將成爲變量的別名。當你說:

void M(ref int x) { ...} 
... 
int y = 123; 
M(ref y); 

你說的話是「x和y現在同一變量」。他們都提到相同的存儲位置

我發現比理解別名是如何實際實現的更容易理解 - 通過將變量的託管地址傳遞給形式參數。

這是明確的嗎?

+0

超級清晰!謝謝 :-) – stiank81 2010-02-24 21:13:52