Struct和Class基本上一樣
除了...
不同之處 | Struct | Class |
型態 | 值類型 | 參考類型 |
記憶體位置 | Stack上 | Heap上 |
繼承 | 只能實現Interface | 可繼承也可實現Interface |
NULL | 不能NULL | 可為NULL |
幾個範例來說明:Struct和Class存放記憶體位置
public class ClassA
{
}
public struct StructType
{
public ClassA a { get; set; }
}
(Struct)範例一:
Equals
方法比較存放在 Stack 執行個體是否一樣
創建兩個 Struct 物件,並且比較可以得到 True
[TestMethod]
public void StructEquals1()
{
StructType s = new StructType();
StructType s1 = new StructType();
Assert.IsTrue(s.Equals(s1));
}
s
和s1
的 Value都是一樣
如下圖:
(Struct)範例二:
[TestMethod]
public void StructEquals2()
{
StructType s = new StructType();
StructType s1 = new StructType();
s.a = new ClassA();
Assert.AreEqual(s.Equals(s1),false);
}
s.a
動態配置一個記憶體位置 而 s1.a
並沒有
所以兩個的Value不一樣
如下圖:
(Struct)範例三:
[TestMethod]
public void StructEquals3()
{
StructType s = new StructType();
StructType s1 = new StructType();
ClassA aObj = new ClassA();
s.a = aObj;
s1.a = aObj;
Assert.IsTrue(s.Equals(s1));
}
如果我們用s
和s1
兩個StructType
結構,動態分配一個aObj
物件並把 s.a
,s1.a
都指向他
我們在比較兩個結構會發現答案是true
一樣
如圖:
(Class)範例:
[TestMethod]
public void ClassEqualsTest()
{
ClassType c = new ClassType();
ClassType c1 = new ClassType();
Assert.AreEqual(c.Equals(c1),false);
}
可看到c
和c1
都指向不同記憶體位置
AreEqual
方法比較 Stack上指向記憶體位置是否相同
結果是不同!!
如圖:
Heap和Stack記憶體存放方式在其他語言中都是通用的概念,可說相當重要!!
另外如果想了解更多Struct和Class細節可看看小弟之前寫的 記憶體Heap,Stack解說
2019/01/20補充 Sturct和Class 在差別使用上Property
在SO上看到一個問題 Are properties always immutable?
最主要問題是說 為什麼 Sturct和Class 都使用UpdateVal
方法,但一個值會更新 一個卻不會
為此我寫了個簡單例子來釐清此問題.
public class MyClass
{
public StructA structA { get; set; }
public ClassA classA { get; set; }
}
public struct StructA
{
public int iVal { get; private set; }
public void UpdagteVal(int input)
{
iVal = input;
}
}
public class ClassA
{
public int iVal { get; private set; }
public void UpdagteVal(int input)
{
iVal = input;
}
}
下面例子
myClass.structA
和 myClass.classA
都呼叫 UpdagteVal
方法但為什麼一個會更新一個確不會呢?
int updateVal = 100;
MyClass myClass = new MyClass()
{
classA = new ClassA()
};
myClass.structA.UpdagteVal(updateVal);
myClass.classA.UpdagteVal(updateVal);
Assert.AreEqual(updateVal, myClass.classA.iVal);
Assert.AreEqual(0, myClass.structA.iVal); // structA 等於0 是因為 Property 其實也是方法,struct使用會拷貝一份資料給另一個值
//所以 myClass.structA.UpdagteVal 此動作侍衛另一個 structA 更新
原因探討:
我們知道屬性(Property)這個語法糖,是簡化GetValue和SetValue方法(所以本質上是方法)
最終會產生如下的程式碼
private StructA _structA;
public StructA GetStructA()
{
return _structA;
}
public void SetStructA(StructA val)
{
_structA = val;
}
當你使用myClass.classA
屬性會返回一個myClass.classA
實例並呼叫 UpdagteVal
方法是對於 classA
這個物件做更新.
但你使用 myClass.structA
屬性返回 myClass.structA
時,會先執行一步Clone此實例,所以會造成UpdagteVal
方法更新值不是原本的實例而是Clone的實例.
原始碼 Github連結
如果本文對您幫助很大,可街口支付斗內鼓勵石頭^^