C# 泛型 值型別和引用型別 堆和棧 裝箱和拆箱 委託和事件 Equals 與==
C#中Equals 與== 的區別
對於值型別來說,Equals與==兩者比較的都是“內容”是否相同,即值是否一樣,很顯然此時兩者是同一個意思。
對於引用型別來說,==(等號)比較的是兩個變數的“引用” 是否一樣,也就是比較引用的“地址”是否相同。而equals()仍然比較的是變數的 “內容” 是否一樣。
以string為例
C# 泛型
優點:
1.使用泛型類、方法,我們可以極大提高程式碼的重用性,不需要對型別不同程式碼相同(僅型別引數不同)的程式碼寫多次。
2.建立泛型類,可在編譯時建立型別安全的集合
值型別和引用型別
在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方法。 偵聽者怎麼樣用程式的語言告訴系統呢,就是你這裡寫好的 += 語句了,那有一天,偵聽者可能不感興趣這個事件了, 那麼他可以取消掉自己的註冊。 用 -= 咯
+=就是發生新事件的同時通知你;
-=就是發生新事件的同時不通知你;
+=就是發生這個事件的同時要通知你,-=就是發生這個事件不再來通知你了。