国产片侵犯亲女视频播放_亚洲精品二区_在线免费国产视频_欧美精品一区二区三区在线_少妇久久久_在线观看av不卡

服務器之家:專注于服務器技術及軟件下載分享
分類導航

PHP教程|ASP.NET教程|Java教程|ASP教程|編程技術|正則表達式|C/C++|IOS|C#|Swift|Android|VB|R語言|JavaScript|易語言|vb.net|

服務器之家 - 編程語言 - C# - c#基礎系列之值類型和引用類型的深入理解

c#基礎系列之值類型和引用類型的深入理解

2022-03-01 13:33大菜 C#

這篇文章主要給大家介紹了關于c#基礎系列之值類型和引用類型的相關資料,文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋友們下面隨著小編來一起學習學習吧

前言

不知不覺已經踏入坑已10余年之多,對于c#多多少少有一點自己的認識,寫出來渴求同類抨擊,對自己也算是個十年之癢的一個總結。

c#把數據類型分為值類型和引用類型

1.1:從概念上來看,其區別是值類型直接存儲值,而引用類型存儲對值的引用。

1.2:這兩種類型在內存的不同地方,值類型存儲在堆棧中,而引用類型存儲在托管對上。存儲位置的不同會有不同的影響。

下面話不多說了,來一起看看詳細的介紹吧

基本概念

clr支持兩種類型:值類型和引用類型。 面試過很多5年左右的同學,有很多連值類型和引用類型的基本概念都回答不上來,難道現在的c#開發人員基礎這么弱了嗎?還是大家都不重視基礎呢?這個隨便找一篇博客都可以基礎入門的。

c#基礎系列之值類型和引用類型的深入理解

引用類型

哪些類型是引用類型呢?其實一個可以稱為”類“的類型都是引用類型。 引用類型總是從托管堆上分配的,常用的語法就是new xx(). c#的new 操作符會返回對象的指針 - 也就是指向對象數據的內存地址的一個引用。引用類型的傳遞其實傳遞的是對象的指針(string類型比較特殊),所以在特定的場景下性能是高于值類型的。一個引用類型在創建時默認為null,也就是說當前變量不指向一個有效的對象,也就是我們常遇到的異常“未將對象引用設置到對象的實例”。

值類型

因為引用類型變量都需要進行一次堆內存的分配,這會給gc造成很大的壓力,所以clr提供了輕量級類型“值類型”。 值類型一般在線程棧上分配。(注意:值類型可以嵌入一個引用對象中)一個值類型變量其實就包含了值類型實例的值,所以它沒有引用類型的指針(大家猜想值類型需不需要類型對象指針呢?)

相同點和不同點

相同點

  • 值類型和引用類型都是system.object的子類
  • 值類型和引用類型都可以繼承接口。(很多人都認為值類型不能繼承接口)
?
1
2
3
4
5
6
7
8
9
10
11
interface itest
{
void test();
}
struct teststruct : itest
{
public void test()
{
throw new notimplementedexception();
}
}

不同點

  • 值類型分配在堆棧上,引用類型是在托管堆上分配的。這里需要指出一點:如果一個引用類型中的某個屬性是值類型,這個值類型的屬性是分配在托管堆上的。
  • 所有的值類型都是隱式密封的(sealed),例如 :你不可能繼承int 來構造自己的類型。
  • 值類型的每一次賦值都會執行一次逐字段的復制,所以如果是頻繁賦值也會造成性能上的壓力,引用類型的賦值只是指針的傳遞,其實也是生成新的指針實例。
  • 引用類型額外有類型對象指針和同步塊索引,值類型是沒有的。所以我們平時使用lock 鎖的對象不可能是值類型,因為值類型沒有同步塊索引

c#基礎系列之值類型和引用類型的深入理解

性能

有的同學說值類型的性能高于引用類型,那為什么不都用值類型呢?引用類型也是如此。任何東西都有兩面性,只有合適的類型,沒有萬能的類型。

1、值類型:所謂的.net framework中的“輕量類型”,為什么說是“輕量”呢,這和他的內存分配有直接關系,因為值類型是分配在棧上,所以在gc的控制之外,不會對gc造成壓力。那是不是可以隨便用呢?當然不是,舉個例子:我自定義一個struct 類型作為一個方法的參數會發生什么呢?每次調用都會發生全字段的賦值,這是不可接受的,這也是典型的值類型勿用場景。

2、引用類型:引用類型分配在堆中,所以會影響gc,如果頻繁的初始化引用類型,對gc的壓力是很大的,因為每一次分配都有可能會強制執行一次垃圾收集操作。另外提一點,引用類型的所占內存,并非所有屬性/字段的和,堆上分配的每個對象都有一些額外的成員,這些成員必須初始化。(類型對象指針和內存塊索引)。

3、裝箱拆箱:所謂裝箱就是將值類型轉化為引用類型的過程。拆箱則相反(只是概念上相反,實際編譯器的操作不一樣)。有的同學說裝箱拆箱影響性能,那到底是裝箱影響呢還是拆箱呢還是都影響呢?

裝箱發生了什么過程呢:

  • 在托管堆中分配好內存,分配的內存量是值類型的各個字段需要的內存量加上托管堆上所以對象的兩個額外成員(類型對象指針,同步塊索引)需要的內存量
  • 值類型的字段復制到新分配的堆內存中
  • 返回對象的地址,這個地址就是這個對象的引用

拆箱發生了什么過程呢:

  • 獲取已經裝箱的值類型實例的指針
  • 把獲取到的值復制到棧

所以裝箱是比較耗費性能的,還有可能引發一次gc操作,而拆箱只是一個獲取指針的過程耗費資源要比裝箱小的多。注意:一個對象拆箱之后只能還原為原先未裝箱之前的類型,例如:你不能把int32類型裝箱后還原為int16類型。 所以面試的時候可以和面試官裝b一下了~~

c#基礎系列之值類型和引用類型的深入理解

測試例子

值類型引用類型分別初始化n次消耗的時間,代碼如下

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
static void main(string[] args)
 {
 console.writeline("test start");
 int totalcount = 10000000;
 stopwatch sw = new stopwatch();
 sw.start();
 for (int i = 0; i < totalcount; i++)
 {
  testref temp = new testref() { id = i, name = "test" };
 }
 sw.stop();
 console.writeline($"引用類型耗時:{sw.elapsedmilliseconds}");
 sw.reset();
 sw.start();
 
 for (int i = 0; i < totalcount; i++)
 {
  testval temp = new testval() { id = i, name = "test" };
 }
 sw.stop();
 console.writeline($"值類型耗時:{sw.elapsedmilliseconds}");
 console.read();
 }
 
 class testref
 {
 public int id { get; set; }
 public string name { get; set; }
 }
 struct testval
 {
 public int id { get; set; }
 public string name { get; set; }
 }

運行結果:

引用類型耗時:205
值類型耗時:152

可見初始化速度值類型是優于引用類型的,也可能是引用類型引發了gc導致。

作為方法參數傳遞,代碼如下:

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
static void main(string[] args)
 {
 console.writeline("test start");
 long totalcount = 1000000000;
 stopwatch sw = new stopwatch();
 sw.start();
 
 testref tempref = new testref() { id = 1, name = "test" , name2="r3rewfdsafdsa", name3="fsrewfdsafdsafdsa", name4="fdafdasfdsafdsa", name5="432tretsfds", name6="fdsafdasfdasfd" };
 for (int i = 0; i < totalcount; i++)
 {
  testr(tempref);
 }
 sw.stop();
 console.writeline($"引用類型耗時:{sw.elapsedmilliseconds}");
 sw.reset();
 sw.start();
 testval tempval = new testval() { id = 1, name = "test", name2 = "r3rewfdsafdsa", name3 = "fsrewfdsafdsafdsa", name4 = "fdafdasfdsafdsa", name5 = "432tretsfds", name6 = "fdsafdasfdasfd" };
 for (int i = 0; i < totalcount; i++)
 {
  testv(tempval);
 }
 sw.stop();
 console.writeline($"值類型耗時:{sw.elapsedmilliseconds}");
 console.read();
 }
 static void testr(testref r)
 {
 return;
 }
 static void testv(testval v)
 {
 return;
 }
 
 class testref
 {
 public int id { get; set; }
 public string name { get; set; }
 public string name2 { get; set; }
 public string name3 { get; set; }
 public string name4 { get; set; }
 public string name5 { get; set; }
 public string name6 { get; set; }
 }
 struct testval
 {
 public int id { get; set; }
 public string name { get; set; }
 public string name2 { get; set; }
 public string name3 { get; set; }
 public string name4 { get; set; }
 public string name5 { get; set; }
 public string name6 { get; set; }
 }

運行結果:

引用類型耗時:4437
值類型耗時:5226

可見在普通情況下,作為參數值類型和引用類型用時差距不大,但是,如果值類型的實例屬性比較多的情況下差距降進一步拉大。

非正式環境測試用例,結果僅供參考

應用場景

不止是面試的時候經常問應用場景這個問題,就是自己平時寫程序也應該清楚。程序設計選擇的時候大部分場景都是用引用類型,但是如果你滿足下列條件,值類型可能更適用:

  • 類型不會派生出任何其它類型,也就是說不會有被繼承的可能
  • 類型不需要繼承其他類型
  • 類型的實例比較小,并且不會被作為方法參數,不會被頻繁賦值
  • 你永遠不會用到類型釋放時候的通知,因為引用類型利用析構函數可以利用其他手段可以得到釋放時候的通知。
  • 如果你的類型實例不會發生值的改變或者可以認為是readonly性質的,值類型或許是首選。

其他

  • 所有的值類型都從system.valuetype 派生,system.valuetype繼承system.object,但是system.valuetype 重寫了equals 和gethashcode 方法,其實在這里才是真正和引用類型的分割線。
  • 因為值類型有裝箱拆箱的操作,所以像arraylist這樣的集合性能是非常令人擔憂的。所以c# 2.0 出現了泛型 例如:list .....來保證了類型安全,同時又避免了拆箱裝箱,因為不是我定義的類型 ,你tmd根本連編譯器那一關都過不了 哈哈哈~~~~

順便說一句,好久不寫博客,樣式真實花時間啊,后來干脆寫markdown格式的,請大家見諒!!

總結

以上就是這篇文章的全部內容了,希望本文的內容對大家的學習或者工作具有一定的參考學習價值,如果有疑問大家可以留言交流,謝謝大家對服務器之家的支持。

原文鏈接:https://www.cnblogs.com/zhanlang/p/9603592.html

延伸 · 閱讀

精彩推薦
  • C#C#實現XML文件讀取

    C#實現XML文件讀取

    這篇文章主要為大家詳細介紹了C#實現XML文件讀取的相關代碼,具有一定的參考價值,感興趣的小伙伴們可以參考一下...

    Just_for_Myself6702022-02-22
  • C#Unity3D實現虛擬按鈕控制人物移動效果

    Unity3D實現虛擬按鈕控制人物移動效果

    這篇文章主要為大家詳細介紹了Unity3D實現虛擬按鈕控制人物移動效果,文中示例代碼介紹的非常詳細,具有一定的參考價值,感興趣的小伙伴們可以參考一...

    shenqingyu060520232410972022-03-11
  • C#C#設計模式之Visitor訪問者模式解決長隆歡樂世界問題實例

    C#設計模式之Visitor訪問者模式解決長隆歡樂世界問題實例

    這篇文章主要介紹了C#設計模式之Visitor訪問者模式解決長隆歡樂世界問題,簡單描述了訪問者模式的定義并結合具體實例形式分析了C#使用訪問者模式解決長...

    GhostRider9502022-01-21
  • C#深入解析C#中的交錯數組與隱式類型的數組

    深入解析C#中的交錯數組與隱式類型的數組

    這篇文章主要介紹了深入解析C#中的交錯數組與隱式類型的數組,隱式類型的數組通常與匿名類型以及對象初始值設定項和集合初始值設定項一起使用,需要的...

    C#教程網6172021-11-09
  • C#C#裁剪,縮放,清晰度,水印處理操作示例

    C#裁剪,縮放,清晰度,水印處理操作示例

    這篇文章主要為大家詳細介紹了C#裁剪,縮放,清晰度,水印處理操作示例,具有一定的參考價值,感興趣的小伙伴們可以參考一下...

    吳 劍8332021-12-08
  • C#WPF 自定義雷達圖開發實例教程

    WPF 自定義雷達圖開發實例教程

    這篇文章主要介紹了WPF 自定義雷達圖開發實例教程,本文介紹的非常詳細,具有參考借鑒價值,需要的朋友可以參考下...

    WinterFish13112021-12-06
  • C#C#通過KD樹進行距離最近點的查找

    C#通過KD樹進行距離最近點的查找

    這篇文章主要為大家詳細介紹了C#通過KD樹進行距離最近點的查找,具有一定的參考價值,感興趣的小伙伴們可以參考一下...

    帆帆帆6112022-01-22
  • C#C# 實現對PPT文檔加密、解密及重置密碼的操作方法

    C# 實現對PPT文檔加密、解密及重置密碼的操作方法

    這篇文章主要介紹了C# 實現對PPT文檔加密、解密及重置密碼的操作方法,非常不錯,具有參考借鑒價值,需要的朋友可以參考下...

    E-iceblue5012022-02-12
主站蜘蛛池模板: 亚洲永久免费 | 久久国产精品亚洲 | 99精品国产高清在线观看 | 国产精品久久久久无码av | 精品久久一区二区三区 | 午夜在线影院 | 日韩视频在线免费观看 | 久久99精品久久久久久国产越南 | 国产综合精品一区二区三区 | 色橹橹欧美在线观看视频高清 | 成人va在线观看 | 黄色av免费 | 亚洲男人av | 91天堂网| 日美毛片 | 国产精品久久久久久久久 | 99久久精品免费看国产四区 | 亚洲精品一区二区三区蜜桃久 | 真实的国产乱xxxx在线 | 色站综合 | 日韩在线观看一区 | 久热精品在线视频 | 99r在线| 久久久精品 | 亚洲激情在线 | 国产毛片一区二区 | 在线色网站 | 亚洲午夜视频 | 国产精品成人一区二区 | 国产精品自拍视频 | 国产一区视频在线看 | 国产成人免费视频网站高清观看视频 | 成人中文视频 | 亚洲欧美日韩在线一区二区三区 | 欧美日韩高清在线观看 | 99视频在线免费观看 | 欧美视频免费看 | 欧美成人a∨高清免费观看 国产99久久 | 亚洲国产精品久久久久久6q | 在线日韩一区 | 国产超碰人人爽人人做人人爱 |