參考轉(zhuǎn)載文檔:
https://docs.microsoft.com/zh-cn/dotnet/csharp/programming-guide/classes-and-structs/structs
https://docs.microsoft.com/zh-cn/dotnet/csharp/programming-guide/classes-and-structs/using-structs
注意
- 關(guān)于ValueType下面要用:盡管ValueType是值類型的隱式基類, 但無法創(chuàng)建直接從ValueType繼承的類。 相反, 單個編譯器提供語言關(guān)鍵字或構(gòu)造 (例如
struct, 在StructureC#和 ...End Structure在 Visual Basic) 支持創(chuàng)建值類型。
1. 結(jié)構(gòu)體特點(diǎn):
- 結(jié)構(gòu)體是值類型,類是引用類型。
-
一個結(jié)構(gòu)無法繼承自另一個結(jié)構(gòu)或類,并且它不能為類的基類。 所有結(jié)構(gòu)都直接繼承自 ValueType,后者繼承自 Object。 -
結(jié)構(gòu)可以實(shí)現(xiàn)接口。 - 結(jié)構(gòu)不能為
null,并且不能向結(jié)構(gòu)變量分配null,除非將變量聲明為可為 null 的類型。 - 結(jié)構(gòu)在分配時進(jìn)行復(fù)制。 將結(jié)構(gòu)分配給新變量時,將復(fù)制所有數(shù)據(jù),并且對新副本所做的任何修改不會更改原始副本的數(shù)據(jù)。 在處理值類型的集合(如
Dictionary<string, myStruct>)時,請務(wù)必記住這一點(diǎn)。 - 在初始化方面:
- 在結(jié)構(gòu)體聲明中,除非將字段聲明為 const 或 static,否則無法初始化。
- 結(jié)構(gòu)不能聲明無參數(shù)構(gòu)造函數(shù)或一個finalizer。
- 結(jié)構(gòu)可以聲明具有參數(shù)的構(gòu)造函數(shù)。但必須顯式初始化所有成員,否則一個或更多的成員將不被分配,并且不能使用結(jié)構(gòu),這會生成編譯器錯誤 CS0171。
解釋:與類不同,可以對結(jié)構(gòu)進(jìn)行實(shí)例化,而無需使用 new 運(yùn)算符。 在這種情況下,沒有調(diào)用任何構(gòu)造函數(shù),從而提高了分配效率。 但是,字段將保持為未分配狀態(tài)且必須在在初始化所有字段之后才可使用對象。 這包括無法通過屬性獲取或設(shè)置值。如果使用默認(rèn)的無參數(shù)構(gòu)造函數(shù)實(shí)例化結(jié)構(gòu)對象,則根據(jù)成員的默認(rèn)值分配所有成員。這也解釋了上面三點(diǎn)。
此示例同時使用了默認(rèn)構(gòu)造函數(shù)和參數(shù)構(gòu)造函數(shù)來演示 struct 初始化:
public struct Coords
{
public int x, y;
public Coords(int p1, int p2)
{
x = p1;
y = p2;
}
}
// Declare and initialize struct objects.
class TestCoords
{
static void Main()
{
// Initialize.
var coords1 = new Coords();
var coords2 = new Coords(10, 10);
// Display results.
Console.Write("Coords 1: ");
Console.WriteLine($"x = {coords1.x}, y = {coords1.y}");
Console.Write("Coords 2: ");
Console.WriteLine($"x = {coords2.x}, y = {coords2.y}");
// Keep the console window open in debug mode.
Console.WriteLine("Press any key to exit.");
Console.ReadKey();
}
}
/* Output:
Coords 1: x = 0, y = 0
Coords 2: x = 10, y = 10
*/
此示例演示了一個特定于結(jié)構(gòu)的功能。 此功能可以創(chuàng)建 Coords 對象,而無需使用 new 運(yùn)算符。 如果將 struct 替換為 class,程序?qū)⒉粫M(jìn)行編譯:
public struct Coords
{
public int x, y;
public Coords(int p1, int p2)
{
x = p1;
y = p2;
}
}
// Declare a struct object without "new".
class TestCoordsNoNew
{
static void Main()
{
// Declare an object.
Coords coords1;
// Initialize.
coords1.x = 10;
coords1.y = 20;
// Display results.
Console.Write("Coords 1: ");
Console.WriteLine($"x = {coords1.x}, y = {coords1.y}");
// Keep the console window open in debug mode.
Console.WriteLine("Press any key to exit.");
Console.ReadKey();
}
}
// Output: Coords 1: x = 10, y = 20
2. 結(jié)構(gòu)體和類的選擇:
首先明確,類的對象是存儲在堆空間中,結(jié)構(gòu)存儲在棧中。堆空間大,但訪問速度較慢,棧空間小,訪問速度相對更快。故而,當(dāng)我們描述一個輕量級對象的時候,結(jié)構(gòu)可提高效率,成本更低。當(dāng)然,這也得從需求出發(fā),假如我們在傳值的時候希望傳遞的是對象的引用地址而不是對象的拷貝,就應(yīng)該使用類了。
1、當(dāng)堆棧的空間很有限,且有大量的邏輯對象時,創(chuàng)建類要比創(chuàng)建結(jié)構(gòu)好一些
2、對于點(diǎn)、矩形和顏色這樣的輕量對象,假如要聲明一個含有許多個顏色對象的數(shù)組,則CLR需要為每個對象分配內(nèi)存,在這種情況下,使用結(jié)構(gòu)的成本較低
3、大多數(shù)情況下,目標(biāo)類型只是含有一些數(shù)據(jù),或者以數(shù)據(jù)為主