亚洲乱码中文字幕综合,中国熟女仑乱hd,亚洲精品乱拍国产一区二区三区,一本大道卡一卡二卡三乱码全集资源,又粗又黄又硬又爽的免费视频

c#中值類(lèi)型和引用類(lèi)型的基礎(chǔ)教程

 更新時(shí)間:2020年06月09日 09:07:59   作者:老胡寫(xiě)代碼  
這篇文章主要給大家介紹了關(guān)于c#中值類(lèi)型和引用類(lèi)型的基礎(chǔ)教程,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面來(lái)一起學(xué)習(xí)學(xué)習(xí)吧

前言

值類(lèi)型和引用類(lèi)型,是c#比較基礎(chǔ),也必須掌握的知識(shí)點(diǎn),但是也不是那么輕易就能掌握,今天跟著老胡一起來(lái)看看吧。 

典型類(lèi)型

首先我們看看這兩種不同的類(lèi)型有哪些比較典型的代表。 

典型值類(lèi)型

int, long, float, double等原始類(lèi)型中表示數(shù)字的類(lèi)型都是值類(lèi)型,表示時(shí)間的datatime也是值類(lèi)型,除此之外我們還可以通過(guò)關(guān)鍵字struct自定義值類(lèi)型。 

典型引用類(lèi)型

原始類(lèi)型中,array, list, dictionary, queue, stack和string都是引用類(lèi)型,除此之外我們通過(guò)關(guān)鍵字class自定義引用類(lèi)型。 

基類(lèi)

c#中所有的類(lèi)型都最終繼承自O(shè)bject,這是沒(méi)有疑問(wèn)的,但是這其中還有些微區(qū)別。 

值類(lèi)型基類(lèi)

對(duì)于值類(lèi)型來(lái)說(shuō),除了最終繼承自O(shè)bject,還繼承自ValueType,繼承鏈如下

但是請(qǐng)不要誤解,這里僅僅指的是值類(lèi)型天然是ValueType,但是不代表值類(lèi)型能夠這么聲明

struct Struct1 : ValueType
{

}

這樣是會(huì)引起編譯錯(cuò)誤的,值類(lèi)型不能繼承任何其他類(lèi)型,值類(lèi)型只能實(shí)現(xiàn)接口,不能繼承自其它類(lèi)型。只有引用類(lèi)型既可以實(shí)現(xiàn)接口也能繼承自其它類(lèi)型。順便說(shuō)一下,還有一點(diǎn)比較重要的是,ValueType重寫(xiě)了Object基類(lèi)的Equals方法和GetHashCode方法,所以當(dāng)使用Equals比較兩個(gè)值類(lèi)型的時(shí)候,系統(tǒng)會(huì)比較兩個(gè)值類(lèi)型的各個(gè)屬性是否相等,再返回結(jié)果,這就是所謂的相等性。與此相對(duì),引用類(lèi)型在使用Equals的時(shí)候,會(huì)在后臺(tái)調(diào)用object.ReferenceEquals,換言之,引用類(lèi)型在比較相等性的時(shí)候會(huì)考慮同一性。 

引用類(lèi)型基類(lèi)

對(duì)于引用類(lèi)型就沒(méi)有那么麻煩,引用類(lèi)型不會(huì)繼承自ValueType。引用類(lèi)型可以繼承其他類(lèi)型。 

在內(nèi)存中的表現(xiàn)

我們都知道,C#將內(nèi)存分為了兩部分,一個(gè)是Stack,另外一個(gè)是Managed Heap。一般來(lái)說(shuō),用于函數(shù)調(diào)用進(jìn)棧,函數(shù)返回出棧,用的是Stack,而當(dāng)創(chuàng)造一個(gè)新的實(shí)例時(shí),會(huì)根據(jù)創(chuàng)建的實(shí)例屬于值類(lèi)型還是引用類(lèi)型決定使用Stack還是Managed Heap。 

值類(lèi)型在內(nèi)存中

當(dāng)創(chuàng)建一個(gè)值類(lèi)型對(duì)象時(shí),c#會(huì)在Stack上面創(chuàng)建一塊空間,這塊空間就存放這個(gè)值類(lèi)型對(duì)象。
int是一個(gè)典型的值類(lèi)型,如下語(yǔ)句

int age = 10;

會(huì)存在于內(nèi)存中的Stack上面。

如果把值類(lèi)型的實(shí)例賦值給另外一個(gè)值類(lèi)型,那么效果就是復(fù)制一個(gè)新的值類(lèi)型實(shí)例。

int myAge = age;


 

引用類(lèi)型在內(nèi)存中

與值類(lèi)型在內(nèi)存中的表現(xiàn)不一樣,創(chuàng)建一個(gè)引用類(lèi)型的實(shí)例,不但會(huì)在Stack上面新建一個(gè)引用,還會(huì)在Heap上面劃分出內(nèi)存以容納該引用類(lèi)型實(shí)例。用戶(hù)在使用的時(shí)候通過(guò)Stack上面的變量間接引用該實(shí)例。

class Author
{
	public string Name{get;set;}
	public int Age{get;set;}
}

Author author = new Author(){Name="deatharthas", Age= 32};

注意看和值類(lèi)型在內(nèi)存中的區(qū)別,引用類(lèi)型通過(guò)Stack上的變量訪問(wèn)位于Heap上面的實(shí)例。

在賦值的時(shí)候,拷貝的僅僅是Stack上面的變量,新拷貝出來(lái)的對(duì)象和舊的對(duì)象指向的是同一塊內(nèi)存。

Author myAuthor = author;

這個(gè)時(shí)候,author和myAuthor指向同一塊內(nèi)存,稱(chēng)為同一性,通過(guò)調(diào)用

object.ReferenceEquals(myAuthor, author);

可以得到驗(yàn)證。

但可能有細(xì)心的朋友會(huì)有疑問(wèn)了,不是說(shuō)int是值類(lèi)型,值類(lèi)型是存在于Stack上面的嗎?為什么在author類(lèi)里面,它會(huì)在Heap里面呢?贊一個(gè)細(xì)心!值類(lèi)型一般存在于Stack上面,但如果某個(gè)值類(lèi)型包含于引用類(lèi)型,那么它也會(huì)隨著那個(gè)引用類(lèi)型存放在Heap上面。 

當(dāng)參數(shù)時(shí)的行為區(qū)別

c#中的參數(shù)傳遞默認(rèn)都是傳值(by value),但是根據(jù)所傳遞對(duì)象是值類(lèi)型還是引用類(lèi)型,它們的行為還是有所區(qū)別,現(xiàn)在我們來(lái)看看。

值類(lèi)型當(dāng)參數(shù)

值類(lèi)型當(dāng)參數(shù)的時(shí)候,傳遞到函數(shù)內(nèi)部的是一份值類(lèi)型的拷貝,所以在函數(shù)內(nèi)部修改這個(gè)拷貝不會(huì)影響原對(duì)象。除非我們?cè)趥鬟f參數(shù)的時(shí)候使用了ref或者out。

引用類(lèi)型當(dāng)參數(shù)

如果參數(shù)是引用類(lèi)型,傳遞到函數(shù)內(nèi)部的依然是一份拷貝,但是這個(gè)拷貝是其在Stack上面的變量的拷貝,就像上面的賦值那個(gè)例子。所以這個(gè)時(shí)候這份拷貝其實(shí)和原對(duì)象指向同一塊內(nèi)存(指向同一性),修改這個(gè)對(duì)象可以反映到原對(duì)象上面。 

謹(jǐn)慎返回引用類(lèi)型

編程是一項(xiàng)需要謹(jǐn)慎的工作,有時(shí)候我們經(jīng)常會(huì)犯一些錯(cuò)誤,而這些錯(cuò)誤又是那么的不明顯以至于不摔坑幾次,我們根本察覺(jué)不了,考慮下面一個(gè)例子。

 class People
 {
  public string Name { get; set; }
  public int Age { get; set; }
  private People _Father = null;
  public People Father { get { return _Father; } }
  public People(People father)
  {
   _Father = father;
  }
  public void ShowFather()
  {
   Console.WriteLine("father's name is " + Father.Name + " and his age is " + Father.Age);
  }
 }

 class Program
 {  
  static void Main(string[] args)
  {
   People father = new People(null) { Name = "father", Age = 60 };
   People son = new People(father);
   son.ShowFather();
   Console.ReadLine();
  }
 }

看起來(lái)沒(méi)什么問(wèn)題,對(duì)吧?Father沒(méi)有提供setter,似乎是安全的。但是我們?cè)囋囅旅娴拇a。

	static void Main(string[] args)
  {
   People father = new People(null) { Name = "father", Age = 60 };
   People son = new People(father);
   var f = son.Father;
   f.Name="Changed";
   son.ShowFather();
   Console.ReadLine();
  }

看,發(fā)現(xiàn)了什么,外部改變了本來(lái)應(yīng)該被封裝所保護(hù)的Father屬性,封裝被破壞了!

稍微一想我們應(yīng)該能明白這個(gè)道理,F(xiàn)ather屬性返回的拷貝的變量和原Father變量指向同一塊實(shí)例。要想解決這個(gè)問(wèn)題,我們要么返回一個(gè)值類(lèi)型,要么返回一個(gè)全新的對(duì)象。修改Father屬性如下:

public People Father { get { return new People(_Father._Father) { Name = _Father.Name, Age = _Father.Age }; } }

再次測(cè)試,

這次封裝就沒(méi)問(wèn)題了。 

總結(jié)

我們大概知道了值類(lèi)型和引用類(lèi)型的區(qū)別,包括它們的行為,在內(nèi)存的居住方式,以及使用引用類(lèi)型時(shí)可能會(huì)遇到的暗坑,希望大家通過(guò)閱讀這篇文章,能夠加深一些對(duì)它們的了解,少走一些彎路。

今天也簡(jiǎn)單的提到了比較時(shí)的同一性,和預(yù)防封裝被破壞所采用的返回一個(gè)新的實(shí)例拷貝的策略(這個(gè)時(shí)候適合使用DeepCopy),我們之后有機(jī)會(huì)再詳細(xì)聊。

到此這篇關(guān)于c#中值類(lèi)型和引用類(lèi)型的文章就介紹到這了,更多相關(guān)c#值類(lèi)型和引用類(lèi)型內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

相關(guān)文章

  • C#使用符號(hào)表實(shí)現(xiàn)查找算法

    C#使用符號(hào)表實(shí)現(xiàn)查找算法

    本文詳細(xì)講解了C#使用符號(hào)表實(shí)現(xiàn)查找算法,文中通過(guò)示例代碼介紹的非常詳細(xì)。對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下
    2022-04-04
  • Unity實(shí)現(xiàn)顏色漸變滑動(dòng)條

    Unity實(shí)現(xiàn)顏色漸變滑動(dòng)條

    這篇文章主要為大家詳細(xì)介紹了Unity實(shí)現(xiàn)顏色漸變滑動(dòng)條,文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下
    2021-07-07
  • C#使用listView增刪操作實(shí)例

    C#使用listView增刪操作實(shí)例

    這篇文章主要介紹了C#使用listView增刪操作的實(shí)現(xiàn)方法,實(shí)例分析了C#中使用listView控件進(jìn)行動(dòng)態(tài)添加、選中刪除等操作的技巧,具有一定的參考借鑒價(jià)值,需要的朋友可以參考下
    2014-12-12
  • C# 根據(jù)字符串生成二維碼的實(shí)例代碼

    C# 根據(jù)字符串生成二維碼的實(shí)例代碼

    這篇文章主要介紹了C# 根據(jù)字符串生成二維碼的實(shí)例,文中示例代碼非常詳細(xì),幫助大家更好的理解和學(xué)習(xí),感興趣的朋友可以了解下
    2020-07-07
  • 基于Unity Line Renderer組件的常用屬性說(shuō)明

    基于Unity Line Renderer組件的常用屬性說(shuō)明

    這篇文章主要介紹了基于Unity Line Renderer組件的常用屬性說(shuō)明,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過(guò)來(lái)看看吧
    2021-04-04
  • C#使用對(duì)象序列化類(lèi)庫(kù)MessasgePack

    C#使用對(duì)象序列化類(lèi)庫(kù)MessasgePack

    這篇文章介紹了C#使用對(duì)象序列化類(lèi)庫(kù)MessasgePack的方法,文中通過(guò)示例代碼介紹的非常詳細(xì)。對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下
    2022-06-06
  • C#實(shí)現(xiàn)圖形路徑變換的方法

    C#實(shí)現(xiàn)圖形路徑變換的方法

    這篇文章主要介紹了C#實(shí)現(xiàn)圖形路徑變換的方法,涉及C#針對(duì)圖形路徑的相關(guān)操作技巧,需要的朋友可以參考下
    2015-06-06
  • C# 禁用鼠標(biāo)中間鍵的方法

    C# 禁用鼠標(biāo)中間鍵的方法

    關(guān)于?。? System.Windows.Forms.NumericUpDown 控件,如何禁用鼠標(biāo)中間鍵?
    2013-03-03
  • C#中利用Lotus notes公共郵箱發(fā)送郵件的方法

    C#中利用Lotus notes公共郵箱發(fā)送郵件的方法

    這篇文章主要給大家介紹了關(guān)于C#中利用Lotus notes公共郵箱發(fā)送郵件的方法,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定參考學(xué)習(xí)價(jià)值,需要的朋友們下面來(lái)一起看看吧。
    2018-02-02
  • C#利用itext實(shí)現(xiàn)PDF頁(yè)面處理與切分

    C#利用itext實(shí)現(xiàn)PDF頁(yè)面處理與切分

    這篇文章主要介紹了如何在C#中使用itext做一個(gè)pdf的頁(yè)面大小一致性處理,然后再根據(jù)數(shù)據(jù)切分出需要的pdf,感興趣的小伙伴可以了解一下
    2022-04-04

最新評(píng)論