[英]C# struct and class variable value
我知道結構是值類型,而類是引用類型,但是當我執行以下代碼時,為什么我會得到兩個不同的答案
有人可以解釋一下嗎
[struct|class] values {
public int x, y;
public values (int x, int y) {
this.x = x;
this.y = y;
}
}
values v = new values(12, 13);
object o = v;
v.x = 2;
Console.WriteLine(((values)o).x);
產出
什么時候
它是class:輸出是2
它是struct:output是12
有人可以解釋一下嗎?
謝謝
對於struct
或class
,行為不同的一行是
object o = v;
如果“ Values
是引用類型,則o
成為引用v
的副本。 仍然只有1個Values
實例。
如果“ Values
是值類型,則o
成為對實例本身的框式副本的引用。 在這種情況下,分配將創建第二個實例,並在原始實例上執行vx = 2
。 副本不受影響。
您的示例包括裝箱,當您使用values o = v;
時,這是不必要的復雜性values o = v;
您將獲得相同的輸出。 然后,該行將創建普通副本(第二個實例)而無需裝箱。
概括起來:值和引用類型之間的主要區別在於復制語義 。 您會在簡單分配( x = y
)和參數傳遞( foo(x)
)中注意到不同的行為。
您可以期望變量值類型可變。 作為練習,請看f.Myvalue.x = 2;
將Values
作為類或結構
class Foo { public Values MyValue { get; set; } }
使用結構並分配結構(或將其用作方法的參數)時,您將擁有結構的全新副本。 而對於類,則可以為該類分配一個引用。
關鍵線是
object o = v;
當值是struct(或值類型)時,它將導致裝箱值。 根據本 (以下鏈接,你可以找到在年底正是你的問題:))
將值類型的值裝箱包括分配對象實例並將值類型的值復制到該實例中。
因此,您在v中的值將被copied
。 當您在這里拆箱
Console.WriteLine(((values)o).x);
您得到原始的v
值,而不是之后的v
v.x = 2;
因此,struct(或值類型)的答案是12
。
對於類(或引用類型),這非常簡單。 您無需裝箱,只需將其投射到對象即可,因此接下來您將使用此原始v
並更改其值。
給定
SomeStruct s1, s2, s3;
Object o1;
... s1 gets a value somehow, then...
s2 = s1; // Q1
o1 = s1; // Q2
s3 = (SomeStruct)o1; // Q3
語句Q1將通過用s1
相應字段的值覆蓋結構的所有公共字段和私有字段來使結構s2
變異。 語句Q2將生成一個新的堆對象,該對象將像包含SomeStruct
類型的字段SomeStruct
,並通過用s1
的相應字段覆蓋其所有字段來修改該字段。 語句Q3將檢查o1
是否包含“裝箱”的SomeStruct
,如果是,將用裝箱對象中的相應字段覆蓋s3
所有字段。
請注意,盒裝結構位於堆對象中時, 通常不會對其進行修改。 如果有人要說:
var temp = (SomeStruct)o1;
temp.someField = Whatever;
o1 = temp;
該序列將創建一個新的堆對象,該對象將保留原始結構的修改后的副本,但原始的盒裝結構將保持原樣。 但是,有一些方法可以修改裝箱對象中的結構。 在大多數情況下,應該避免使用這種技術,但是應該意識到,不存在非平凡的不可變結構(沒有字段的結構是不可變的,但不是很有用)。 通常,如果希望引用一個結構類型的可變實例,則最好將其封裝在一個簡單的類對象中,例如
class ExposedFieldHolder<T>
{
public T Value;
public ExposedFieldHolder(T v) {Value = v;}
}
如果要擁有一個不可變的實例,則應將其封裝在一個不可變的類對象中
class ImmutableHolder<T>
{
T value;
public T Value { get { return value; } ;
public ImmutableHolder(T v) {value = v;}
override public bool Equals(Object o) {
var other = o as ImmutableHolder<T>;
if (!other) return false;
return Object.Equals(value,other.value);
}
override public int GetHashCode() { return Object.GetHashCode(value); }
}
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.