1. 程式人生 > 實用技巧 >C# 泛型 值型別和引用型別 堆和棧 裝箱和拆箱 委託和事件 Equals 與==

C# 泛型 值型別和引用型別 堆和棧 裝箱和拆箱 委託和事件 Equals 與==

C#中Equals 與== 的區別

對於值型別來說,Equals與==兩者比較的都是“內容”是否相同,即值是否一樣,很顯然此時兩者是同一個意思。

對於引用型別來說,==(等號)比較的是兩個變數的“引用” 是否一樣,也就是比較引用的“地址”是否相同。而equals()仍然比較的是變數的 “內容” 是否一樣。

以string為例

C# 泛型

優點:
1.使用泛型類、方法,我們可以極大提高程式碼的重用性,不需要對型別不同程式碼相同(僅型別引數不同)的程式碼寫多次。
2.建立泛型類,可在編譯時建立型別安全的集合

3.避免裝箱和拆箱操作降低效能,在大型集合中裝箱和拆箱的影響非常大.

值型別和引用型別

在C#中簡單型別,結構型別,列舉型別是值型別;其餘的:介面,類,字串,陣列,委託都是引用型別

byte,short,int,long,float,double,decimal,char,bool 和 struct 統稱為值型別。

string 和 class object統稱為引用型別。

值型別儲存在棧記憶體或堆記憶體之中,而引用型別只能放堆記憶體裡。棧比堆快 值型別快

  • 值型別變數聲明後,不管是否已經賦值,編譯器為其分配記憶體。
  • 引用型別當宣告一個類時,只在棧中分配一小片記憶體用於容納一個地址,而此時並沒有為其分配堆上的記憶體空間。當使用 new 建立一個類的例項時,分配堆上的空間,並把堆上空間的地址儲存到棧上分配的小片空間中。
  • 值型別的例項通常是線上程棧上分配的(靜態分配),但是在某些情形下可以儲存在堆中。
  • 引用型別的物件總是在程序堆中分配(動態分配)

相同點:

引用型別可以實現介面,值型別當中的結構體也可以實現介面;

引用型別和值型別都繼承自System.Object類。

不同點:

幾乎所有的引用型別都直接從System.Object繼承,而值型別則繼承其子類,即 直接繼承System.ValueType。即System.ValueType本身是一個類型別,而不是值型別。其關鍵在於ValueType重寫了Equals()方法,從而對值型別按照例項的值來比較,而不是引用地址來比較。

堆和棧裝箱和拆箱

堆和棧:程式執行時的記憶體區域

我們把記憶體分為堆空間和棧空間。

棧空間比較小,但是讀取速度快

堆空間比較大,但是讀取速度慢

1.棧

棧的特徵:

資料只能從棧的頂端插入和刪除

把資料放入棧頂稱為入棧(push)

從棧頂刪除資料稱為出棧(pop)

2. 堆是一塊記憶體區域,與棧不同,堆裡的記憶體能夠以任意順序存入和移除

3.值型別和引用型別

型別被分為兩種:值型別(整數,bool struct char 小數)和引用型別(string 陣列 自定義的類,內建的類)。

1)值型別只需要一段單獨的記憶體,用於儲存實際的資料,(單獨定義的時候放在棧中)

2)引用型別需要兩段記憶體

第一段儲存實際的資料,它總是位於堆中

第二段是一個引用,指向資料在堆中的存放位置

裝箱就是把“值型別”轉換成“引用型別”(Object);

拆箱就是把“引用型別”轉換成“值型別”;

//裝箱 boxing
int i = 3 ;  //分配在棧上
object o = i ;//隱式裝箱操作,int i 在堆上
object b = (object)i ; //顯示裝箱操作
//拆箱 unboxing
int j = (int) o ;//顯示拆箱(將物件o拆箱為int型別)
 
int k = b ;//error!!, 不能隱式拆箱

拆箱的操作包括

1,檢查物件例項,以卻確保它是給定值型別的裝箱值。

2,將該值從例項複製到值型別變數中。

下面來看看這個例子:

int i=0;
System.Object obj=i;
Console.WriteLine(i+","+(int)obj);

其中共發生了3次裝箱和一次拆箱!^_^,看出來了吧?!
第一次是將i裝箱,第2次是輸出的時候將i轉換成string型別,而string型別為引用型別,即又是裝箱,第三次裝箱就是(int)obj的轉換成string型別,裝箱!
拆箱就是(int)obj,將obj拆箱!!

C#委託(各種lambda事件

很多時候,你自己都不知道用了委託

委託最基本的意思就是自己不想幹(自己乾的無法滿足全部需求),找個人來幹,然後你給那個人給點材料(引數),下達一個結果標準(返回值),

委託就是把函式當變數,說白了就是傳遞一段程式碼到另一個函式內部,在另外一個函式裡去呼叫

所有的非同步都是委託 委託就是函式當入參

委託這個名字可以忘記

委託被各種語法糖遮蔽了=>就是委託匿名委託

事件:

比如MQ的推送也是下面這種

client.MqttMsgPublishReceived -= client_MqttMsgPublishReceived;
client.MqttMsgSubscribed += client_MqttMsgSubscribed;

一個事件可以有很多的偵聽者掛接在上面,這些偵聽者通過註冊自己的事件處理例程來告訴系統說,當這個事件發生的時候請呼叫我的xxx方法。具體到你這裡的程式碼,MqttMsgPublishReceived就是一個事件,偵聽者想要告訴系統說,當我收到MqttMsgPublishReceived的時候請你執行我的client_MqttMsgPublishReceived方法。 偵聽者怎麼樣用程式的語言告訴系統呢,就是你這裡寫好的 += 語句了,那有一天,偵聽者可能不感興趣這個事件了, 那麼他可以取消掉自己的註冊。 用 -= 咯

+=就是發生新事件的同時通知你;

-=就是發生新事件的同時不通知你;

+=就是發生這個事件的同時要通知你,-=就是發生這個事件不再來通知你了。