Struct V.S Class 兩者之間差異

  • 35672
  • 0
  • c#
  • 2019-11-25

StructClass基本上一樣

除了...

 

不同之處 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));
}

ss1的 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));
}

如果我們用ss1兩個StructType結構,動態分配一個aObj物件並把 s.as1.a都指向他

我們在比較兩個結構會發現答案是true一樣

如圖:

(Class)範例:

[TestMethod]
public void ClassEqualsTest()
{
    ClassType c = new ClassType();
    ClassType c1 = new ClassType();

    Assert.AreEqual(c.Equals(c1),false);
}

可看到cc1都指向不同記憶體位置

AreEqual方法比較 Stack上指向記憶體位置是否相同

結果是不同!!

如圖:

Heap和Stack記憶體存放方式在其他語言中都是通用的概念,可說相當重要!!

另外如果想了解更多StructClass細節可看看小弟之前寫的 記憶體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連結


如果本文對您幫助很大,可街口支付斗內鼓勵石頭^^