亚洲香蕉成人av网站在线观看_欧美精品成人91久久久久久久_久久久久久久久久久亚洲_热久久视久久精品18亚洲精品_国产精自产拍久久久久久_亚洲色图国产精品_91精品国产网站_中文字幕欧美日韩精品_国产精品久久久久久亚洲调教_国产精品久久一区_性夜试看影院91社区_97在线观看视频国产_68精品久久久久久欧美_欧美精品在线观看_国产精品一区二区久久精品_欧美老女人bb

首頁 > 編程 > C# > 正文

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

2019-10-29 19:59:14
字體:
來源:轉載
供稿:網友

前言

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

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

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

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

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

基本概念

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

c#,值類型,引用類型

引用類型

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

值類型

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

相同點和不同點

相同點

  • 值類型和引用類型都是System.Object的子類
  • 值類型和引用類型都可以繼承接口。(很多人都認為值類型不能繼承接口)
 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次消耗的時間,代碼如下

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導致。

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

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格式的,請大家見諒??!

總結

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


注:相關教程知識閱讀請移步到c#教程頻道。
發表評論 共有條評論
用戶名: 密碼:
驗證碼: 匿名發表
亚洲香蕉成人av网站在线观看_欧美精品成人91久久久久久久_久久久久久久久久久亚洲_热久久视久久精品18亚洲精品_国产精自产拍久久久久久_亚洲色图国产精品_91精品国产网站_中文字幕欧美日韩精品_国产精品久久久久久亚洲调教_国产精品久久一区_性夜试看影院91社区_97在线观看视频国产_68精品久久久久久欧美_欧美精品在线观看_国产精品一区二区久久精品_欧美老女人bb
国产精品一区二区三区毛片淫片| 欧美中文在线视频| 成人自拍性视频| 日韩高清电影免费观看完整| 欧美性猛交xxxx乱大交极品| 欧美性极品少妇精品网站| 欧美精品第一页在线播放| 欧美日韩亚洲激情| 国产精品v片在线观看不卡| 久久精品91久久香蕉加勒比| 性欧美xxxx| 在线看欧美日韩| 亚洲一区二区三区毛片| 亚洲最新中文字幕| 国产亚洲成精品久久| 68精品国产免费久久久久久婷婷| www.午夜精品| 亚洲肉体裸体xxxx137| 日韩精品高清视频| 成人午夜在线观看| 国产精品91免费在线| 国产精品久久网| 欧美精品在线免费| 日韩在线中文字幕| 成人精品网站在线观看| 亚洲成人999| 日本中文字幕久久看| 国产性色av一区二区| 欧美大全免费观看电视剧大泉洋| 亚洲免费视频网站| 国产精品69av| www.欧美精品一二三区| 91黄色8090| 性色av一区二区三区| 日韩中文字幕在线精品| 日本欧美一级片| 日本一区二区三区四区视频| 国产精品视频自在线| 欧美精品18videos性欧| 91麻豆国产语对白在线观看| 亚洲综合在线小说| 在线播放日韩欧美| 欧美精品日韩www.p站| 欧美日韩激情视频8区| 亚洲综合成人婷婷小说| 久久伊人91精品综合网站| 欧美精品制服第一页| 国产精品96久久久久久| 8x拔播拔播x8国产精品| 亚洲美女在线视频| 精品国产欧美一区二区五十路| 欧美激情亚洲综合一区| 亚洲国产日韩欧美在线99| 久久人人爽亚洲精品天堂| 亚洲国产日韩一区| 岛国av一区二区三区| 国产精品免费看久久久香蕉| 国产精品私拍pans大尺度在线| 中文字幕国产精品| 日韩一区二区三区国产| 国产精品高清网站| 国产精品嫩草影院久久久| 欧美日韩国产丝袜另类| 日韩国产高清污视频在线观看| 精品久久久久久国产| 韩国欧美亚洲国产| 日韩电影免费观看在线观看| 国内精品久久久久影院优| 日韩电影在线观看中文字幕| 成人黄色中文字幕| 日韩激情视频在线| 亚洲视频在线播放| 久久久国产在线视频| 欧美高清激情视频| 日韩av三级在线观看| 日韩视频免费观看| 中文字幕欧美精品日韩中文字幕| 久久手机精品视频| 亚洲自拍小视频| 中文字幕无线精品亚洲乱码一区| 欧美成人精品一区| 久久99久国产精品黄毛片入口| 综合136福利视频在线| 91av视频在线观看| 6080yy精品一区二区三区| 精品国内亚洲在观看18黄| 国产精品久久久久免费a∨| 国产欧亚日韩视频| 久久国产一区二区三区| 不卡av电影院| 欧美精品激情在线| 亚洲无限乱码一二三四麻| www.日韩.com| 亚洲国产欧美精品| 日韩精品一区二区视频| 亚洲人成电影网站色xx| 久久国产精品电影| 久久成人av网站| 国产区精品在线观看| 精品国产一区久久久| 8x海外华人永久免费日韩内陆视频| 在线观看国产欧美| 日韩av免费在线播放| 日韩电影中文字幕一区| 色综合久综合久久综合久鬼88| 色噜噜狠狠狠综合曰曰曰88av| 操人视频在线观看欧美| 国产成人极品视频| 成人午夜激情免费视频| 亚洲第一男人天堂| 777精品视频| 欧美成年人视频| 7777精品久久久久久| 精品福利樱桃av导航| 国产欧美 在线欧美| 欧美精品亚州精品| 日韩欧美在线视频日韩欧美在线视频| 日韩中文在线不卡| 欧美黄色片免费观看| 亚洲午夜未满十八勿入免费观看全集| 亚洲第一中文字幕在线观看| 国产精品第七十二页| 国产精品99久久久久久久久久久久| 亚洲图片欧美午夜| 亚洲国产成人在线播放| 日韩精品中文字幕有码专区| 国内外成人免费激情在线视频| 欧美日韩成人在线播放| 91国偷自产一区二区三区的观看方式| 亚洲欧美精品一区二区| 亚洲欧美精品伊人久久| 国产有码一区二区| 91chinesevideo永久地址| 欧美性生交xxxxxdddd| 色婷婷综合久久久久中文字幕1| 国产精品久久久久久中文字| 国产精品r级在线| 热re99久久精品国产66热| 国产精品视频一区国模私拍| 久久久免费观看| 亚洲成人激情在线观看| 一本色道久久综合狠狠躁篇的优点| 亚洲男人天堂网| 国产精品视频网| 中文字幕精品网| 日韩美女在线观看| 亚洲欧美中文在线视频| 欧美激情一区二区三级高清视频| 一区二区三区www| 精品视频在线观看日韩| 亚洲视频第一页| 国产原创欧美精品| 精品久久久久久亚洲精品| 久久不射热爱视频精品| 伊人久久综合97精品| 亚洲国产一区二区三区四区| 77777少妇光屁股久久一区| 九九精品在线播放| 91沈先生在线观看| 欧美性猛交xxxx黑人| 亚洲欧美三级伦理| 亚洲精品天天看| 国产精品jvid在线观看蜜臀| 日韩av在线导航|