中文字幕av专区_日韩电影在线播放_精品国产精品久久一区免费式_av在线免费观看网站

溫馨提示×

溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊×
其他方式登錄
點擊 登錄注冊 即表示同意《億速云用戶服務條款》

淺談c#中值類型和引用類型

發布時間:2020-07-17 15:22:07 來源:億速云 閱讀:136 作者:小豬 欄目:編程語言

小編這次要給大家分享的是淺談c#中值類型和引用類型,文章內容豐富,感興趣的小伙伴可以來了解一下,希望大家閱讀完這篇文章之后能夠有所收獲。

前言

值類型和引用類型,是c#比較基礎,也必須掌握的知識點,但是也不是那么輕易就能掌握,今天跟著老胡一起來看看吧。 

典型類型

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

典型值類型

int, long, float, double等原始類型中表示數字的類型都是值類型,表示時間的datatime也是值類型,除此之外我們還可以通過關鍵字struct自定義值類型。 

典型引用類型

原始類型中,array, list, dictionary, queue, stack和string都是引用類型,除此之外我們通過關鍵字class自定義引用類型。 

基類

c#中所有的類型都最終繼承自Object,這是沒有疑問的,但是這其中還有些微區別。 

值類型基類

對于值類型來說,除了最終繼承自Object,還繼承自ValueType,繼承鏈如下

淺談c#中值類型和引用類型

但是請不要誤解,這里僅僅指的是值類型天然是ValueType,但是不代表值類型能夠這么聲明

struct Struct1 : ValueType
{

}

這樣是會引起編譯錯誤的,值類型不能繼承任何其他類型,值類型只能實現接口,不能繼承自其它類型。只有引用類型既可以實現接口也能繼承自其它類型。順便說一下,還有一點比較重要的是,ValueType重寫了Object基類的Equals方法和GetHashCode方法,所以當使用Equals比較兩個值類型的時候,系統會比較兩個值類型的各個屬性是否相等,再返回結果,這就是所謂的相等性。與此相對,引用類型在使用Equals的時候,會在后臺調用object.ReferenceEquals,換言之,引用類型在比較相等性的時候會考慮同一性。 

引用類型基類

對于引用類型就沒有那么麻煩,引用類型不會繼承自ValueType。引用類型可以繼承其他類型。 

在內存中的表現

我們都知道,C#將內存分為了兩部分,一個是Stack,另外一個是Managed Heap。一般來說,用于函數調用進棧,函數返回出棧,用的是Stack,而當創造一個新的實例時,會根據創建的實例屬于值類型還是引用類型決定使用Stack還是Managed Heap。 

值類型在內存中

當創建一個值類型對象時,c#會在Stack上面創建一塊空間,這塊空間就存放這個值類型對象。
int是一個典型的值類型,如下語句

int age = 10;

會存在于內存中的Stack上面。

淺談c#中值類型和引用類型

如果把值類型的實例賦值給另外一個值類型,那么效果就是復制一個新的值類型實例。

int myAge = age;

淺談c#中值類型和引用類型
 

引用類型在內存中

與值類型在內存中的表現不一樣,創建一個引用類型的實例,不但會在Stack上面新建一個引用,還會在Heap上面劃分出內存以容納該引用類型實例。用戶在使用的時候通過Stack上面的變量間接引用該實例。

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

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

淺談c#中值類型和引用類型

注意看和值類型在內存中的區別,引用類型通過Stack上的變量訪問位于Heap上面的實例。

在賦值的時候,拷貝的僅僅是Stack上面的變量,新拷貝出來的對象和舊的對象指向的是同一塊內存。

Author myAuthor = author;

淺談c#中值類型和引用類型

這個時候,author和myAuthor指向同一塊內存,稱為同一性,通過調用

object.ReferenceEquals(myAuthor, author);

可以得到驗證。

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

當參數時的行為區別

c#中的參數傳遞默認都是傳值(by value),但是根據所傳遞對象是值類型還是引用類型,它們的行為還是有所區別,現在我們來看看。

值類型當參數

值類型當參數的時候,傳遞到函數內部的是一份值類型的拷貝,所以在函數內部修改這個拷貝不會影響原對象。除非我們在傳遞參數的時候使用了ref或者out。

引用類型當參數

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

謹慎返回引用類型

編程是一項需要謹慎的工作,有時候我們經常會犯一些錯誤,而這些錯誤又是那么的不明顯以至于不摔坑幾次,我們根本察覺不了,考慮下面一個例子。

 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();
  }
 }

淺談c#中值類型和引用類型

看起來沒什么問題,對吧?Father沒有提供setter,似乎是安全的。但是我們試試下面的代碼。

	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();
  }

淺談c#中值類型和引用類型

看,發現了什么,外部改變了本來應該被封裝所保護的Father屬性,封裝被破壞了!

稍微一想我們應該能明白這個道理,Father屬性返回的拷貝的變量和原Father變量指向同一塊實例。要想解決這個問題,我們要么返回一個值類型,要么返回一個全新的對象。修改Father屬性如下:

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

再次測試,

淺談c#中值類型和引用類型

這次封裝就沒問題了。 

總結

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

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

看完這篇關于淺談c#中值類型和引用類型的文章,如果覺得文章內容寫得不錯的話,可以把它分享出去給更多人看到。

向AI問一下細節

免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。

AI

当阳市| 古丈县| 巨鹿县| 三都| 临泽县| 车险| 宁远县| 苍南县| 杭锦后旗| 玉树县| 沾化县| 易门县| 南阳市| 阿勒泰市| 临颍县| 江孜县| 观塘区| 高阳县| 乌拉特中旗| 通化县| 武邑县| 行唐县| 托里县| 西安市| 鹤庆县| 贵阳市| 新安县| 宜丰县| 定结县| 泗水县| 根河市| 徐水县| 广宁县| 东光县| 霍邱县| 栾城县| 隆回县| 宾川县| 南宫市| 蓬溪县| 桃园县|