區(qū)分C# 中的 Struct 和 Class
翻譯自 Manju lata Yadav 2019年6月2日 的博文 《Difference Between Struct And Class In C#》,補充了一些內(nèi)容和示例。
結(jié)構(gòu)體(struct)是類(class)的輕量級版本。結(jié)構(gòu)體是值類型,可用于創(chuàng)建行為類似于內(nèi)置類型的對象。
比較
結(jié)構(gòu)體和類共享許多特性,但與類相比有以下局限性。
- 結(jié)構(gòu)體不能有默認(rèn)構(gòu)造函數(shù)(無參構(gòu)造函數(shù))或析構(gòu)函數(shù),構(gòu)造函數(shù)中必須給所有字段賦值。
public struct Coords
{
public double x;
public double y;
public Coords() //錯誤,不允許無參構(gòu)造函數(shù)
{
this.x = 3;
this.y = 4;
}
public Coords(double x) //錯誤,構(gòu)造函數(shù)中必須給所有字段賦值
{
this.x = x;
}
public Coords(double x) //這個是正確的
{
this.x = x;
this.y = 4;
}
public Coords(double x, double y) //這個是正確的
{
this.x = x;
this.y = y;
}
}
- 結(jié)構(gòu)體是值類型,在賦值時進(jìn)行復(fù)制。
- 結(jié)構(gòu)體是值類型,而類是引用類型。
- 結(jié)構(gòu)體可以在不使用
new操作符的情況下實例化。 例如:
public struct Coords
{
public double x;
public double y;
}
static void Main()
{
Coords p;
p.x = 3;
p.y = 4;
Console.WriteLine($"({p.x}, {p.y})"); // 輸出: (3, 4)
}
- 結(jié)構(gòu)體不能繼承于另一個結(jié)構(gòu)體或者類,類也不能繼承結(jié)構(gòu)體。所有結(jié)構(gòu)體都直接繼承于抽象類 System.ValueType,
System.ValueType又繼承于System.Object。 - 結(jié)構(gòu)體不能是基類,因此,結(jié)構(gòu)體不能是
abstract的,且總是隱式密封的(sealed)。 - 不允許對結(jié)構(gòu)體使用抽象(
abstract)和密封(sealed)修飾符,也不允許對結(jié)構(gòu)體成員使用protected或protected internal修飾符。 - 結(jié)構(gòu)體中的函數(shù)成員不能是抽象的(
abstract)或虛的(virtual),重寫(override)修飾符只允許重寫從System.ValueType繼承的方法。 - 結(jié)構(gòu)體中不允許實例屬性或字段包含初始值設(shè)定項。但是,結(jié)構(gòu)體允許靜態(tài)屬性或字段包含初始值設(shè)定項。 例如:
public struct Coords
{
public double x = 4; //錯誤, 結(jié)構(gòu)體中初始化器不允許實例字段設(shè)定初始值
public static double y = 5; // 正確
public static double z { get; set; } = 6; // 正確
}
- 結(jié)構(gòu)體可以實現(xiàn)接口。
- 結(jié)構(gòu)體可以用作
nullable type(即:Nullable<T>中的T),對其賦值 null 值,參考【Nullable<T> Struct】
什么時候使用結(jié)構(gòu)體或類?
要回答這個問題,我們應(yīng)該很好地理解它們的差異。
| 序號 | 結(jié)構(gòu)體(struct) | 類(class) |
|---|---|---|
| 1 | 結(jié)構(gòu)體是值類型,可以在棧(stack)上分配,也可以在包含類型中內(nèi)聯(lián)分配。 | 類是引用類型,在堆(heap)上分配并垃圾回收。 |
| 2 | 值類型的分配和釋放通常比引用類型的分配和釋放更節(jié)約成本。 | 大的引用類型的賦值比大的值類型的賦值成本更低。 |
| 3 | 在結(jié)構(gòu)體中,每個變量都包含自己的數(shù)據(jù)副本(ref 和 out 參數(shù)變量除外),對一個變量的操作不會影響另一個變量。 | 在類中,兩個變量可以包含同一對象的引用,對一個變量的任何操作都會影響另一個變量。 |
這樣,結(jié)構(gòu)體(struct)只能在確定以下情形時使用:
- 它在邏輯上表示單個值,比如基本類型(
int,double,等等)。 - 它是不可變的(immutable)。
- 它不會頻繁地裝箱和拆箱。
在所有其他情形,應(yīng)該將類型定義為類(class)。
結(jié)構(gòu)體示例:
struct Location
{
public int x, y;
public Location(int x, int y)
{
this.x = x;
this.y = y;
}
}
static void Main()
{
Location a = new Location(20, 20);
Location b = a;
a.x = 100;
Console.WriteLine(b.x);
}
輸出將是 20?!癰” 的值是 “a” 的副本,因此 “b” 不受 “a.x” 更改的影響。但是在類中,輸出將是 100,因為變量 “a” 和 “b” 引用同一個對象。
以下為譯者補充
結(jié)構(gòu)體實例與類實例
結(jié)構(gòu)體實例的內(nèi)存在棧(stack)上進(jìn)行分配,所占用的內(nèi)存隨聲明它的類型或方法一起回收。 這就是在賦值時要復(fù)制結(jié)構(gòu)體的一個原因。 相比之下,類實例的內(nèi)存在堆(heap)上進(jìn)行分配,當(dāng)對類實例的所有引用都超出范圍時,為該類實例分配的內(nèi)存將由公共語言運行時自動回收(垃圾回收)。
結(jié)構(gòu)體實例的值相等性
兩個結(jié)構(gòu)體實例的比較是基于值的比較,而類實例的比較則是對其引用的比較。
若要確定兩個結(jié)構(gòu)體實例中的實例字段是否具有相同的值,可使用 ValueType.Equals 方法。 由于所有結(jié)構(gòu)都隱式繼承自 System.ValueType,因此可以直接在其對象上調(diào)用該方法,如以下示例所示:
public struct Person
{
public string Name;
public int Age;
public Person(string name, int age)
{
Name = name;
Age = age;
}
}
static void Main()
{
Person p1 = new Person("技術(shù)譯站", 100);
Person p2;
p2.Name = "技術(shù)譯站";
p2.Age = 100;
if (p2.Equals(p1))
Console.WriteLine("p2 和 p1 有相同的值。");
Console.ReadKey();
}
// 輸出: p2 和 p1 有相同的值。
System.ValueType 是值類型的隱式基類, 它的 Equals 使用反射實現(xiàn),因為它必須能夠確定任何結(jié)構(gòu)體中有哪些字段。 在創(chuàng)建自己的結(jié)構(gòu)體時,重寫 Equals 方法可以提供特定于你的類型的高效求等算法。
“基于值的相等”這一點和 C# 9.0 中新增的記錄(record) 類型具有相似之處
作者 : Manju lata Yadav
譯者 : 技術(shù)譯民
出品 : 技術(shù)譯站
鏈接 : 英文原文
以上就是區(qū)分C# 中的 Struct 和 Class的詳細(xì)內(nèi)容,更多關(guān)于C# 中 Struct 和 Class的資料請關(guān)注腳本之家其它相關(guān)文章!
相關(guān)文章
C#實現(xiàn)WPS文件轉(zhuǎn)PDF格式的方法示例
這篇文章主要介紹了C#實現(xiàn)WPS文件轉(zhuǎn)PDF格式的方法,涉及C#針對office組件的相關(guān)引用與操作技巧,需要的朋友可以參考下2017-11-11
C#集合根據(jù)對象的某個屬性進(jìn)行去重的代碼示例
當(dāng)根據(jù)對象的Name屬性進(jìn)行去重時,你可以使用以下三種方法:使用Distinct方法和自定義比較器、使用LINQ的GroupBy方法,以及使用HashSet,下面給大家介紹C#集合根據(jù)對象的某個屬性進(jìn)行去重的代碼示例,感興趣的朋友一起看看吧2024-03-03
CefSharp如何進(jìn)行頁面的縮放(Ctrl+滾輪)
CefSharp簡單來說就是一款.Net編寫的瀏覽器包,本文主要介紹了CefSharp如何進(jìn)行頁面的縮放,具有一定的參考價值,感興趣的小伙伴們可以參考一下2021-06-06
asp.net core 使用 tensorflowjs實現(xiàn) face recognition的源代碼
tensorflowjs,在該項目中使用了ml5js這個封裝過的機器學(xué)習(xí)JavaScript類庫, 使用起來更簡單,本文給大家分享asp.net core 使用 tensorflowjs實現(xiàn) face recognition的源代碼,需要的朋友參考下吧2021-06-06
深入DropDownList用法的一些學(xué)習(xí)總結(jié)分析
本篇文章是對DropDownList的用法進(jìn)行了詳細(xì)的分析介紹,需要的朋友參考下2013-06-06

