[C#]C#學習筆記-索引器,指針類型,隱式類型,擴展方法,分部方法,匿名類型
C#學習筆記-索引器,指針類型,隱式類型,擴展方法,分部方法,匿名類型
羅朝輝(http://www.rzrgm.cn/kesalin/)
《C#與.NET高級程序設計》讀書筆記
索引器,指針類型
1,可以使用索引器方法 this[Type param] 來自定義一個類型的索引器。C#編譯器為索引器方法創(chuàng)建了一個名為 Item 的屬性來映射正確的獲取/設置方法。舉例:
public Person this[int index]
{
get { return (Person)list[index];
set { list.Insert(index, value);
}
2,索引器方法可以被重載,也可以可以實現多維的索引器,也可以在接口中定義索引器。
3,運算符重載:[], (), 以及簡寫賦值運算符(+=,-=等)不可重載,而 true, flase 也可以用作運算符。C#中如果一個類型重載了相關的二元運算符,與之對應的簡寫賦值運算符會自動具有相應的新功能。同樣,我們也需要重載前增++或前減--就能自動獲得后增或后減的功能。在C#中重載==運算符時必須同時重載!=運算符(如果不這么做,編譯器會提示的),這規(guī)則適用于所以基于比較的運算符(>, <, >=, <=)。重載運算符在內部是通過隱藏方法來表示的。比如:op_Addition(), op_Equality()等。我們也可以在其他不支持重載運算符的語言中調用這些靜態(tài)隱藏方法。
4,C#還支持自定義轉換,轉換方法必須定義為靜態(tài)的。如將Rectangle 轉換為 Square。與重載運算符一樣,包含 implicit 或 explicit 關鍵字的方法在 CIL 中分別對應專門的指令 op_Implicit 和 op_Explicit。
public static explicit operator Square(Rectangle r)
{
Square s;
s.Length = r.Height;
return s;
}
5,C#也支持原始的指針類型,以及相關的指針操作,我們應該明確設定編譯器的 /unsafe 設置,以表示支持不安全編碼。我們使用 unsafe 關鍵字來特別聲明一個代碼區(qū)塊(包括結構,類,類型成員或參數)為不安全代碼。如下關鍵字用于不安全編碼:stackalloc(直接從調用棧分配內存),fixed(用于將不安全上下文內存中的引用類型變量地址固定,這樣在執(zhí)行過程中垃圾回收器就不會重置該變量的地址)以及 sizeof。
6,預處理指令:在C#中沒有獨立的預處理步驟,而是在編譯器的詞法分析階段處理預處理指令。除了傳統(tǒng)的#define, #if系列,C#還增加了用于標記代碼區(qū)塊的 #region, #endregion預處理指令。
隱式類型
7,var 關鍵字(準確地說 var 不是關鍵字,我們可以聲明名為 var 的變量,參數或字段而編譯器不會報錯):我們可以使用 var 替代正式的數據類型名來局部變量,參數和字段,編譯器會根據用于初始化局部變量的初始值推斷變量的數據類型。隱式類型局部變量是強類型數據。如:
static void DeclareImplicitVars()
{
var myInt = 0;
var myBool = true;
var myString = "It's a string";
}
使用 var 定義隱式類型局部數組時,數組初始化式中的各數組成員必須為同一可推斷的類型。隱式類型局部變量不會默認設置為 System.Object。
var d = new[] {1, 10, 100, 100};
8,使用 var 有一些限制:首先,顯式類型只能應用于方法或者屬性內局部變量的聲明,不能使用 var 來定義返回值,參數的類型或者類型的數據成員。其次 var 進行聲明的局部變量必須在聲明時同時賦值,并且不能以null作為初始值。再次,不能使用C#的?標識來定義可空隱式類型局部變量。
9,隱式類型局部變量的作用:LINQ技術使用查詢表達式,它可以動態(tài)根據查詢本身的格式來創(chuàng)建結果集,這樣我們可以使用 var,從而不需要顯式定義查詢可能會返回的類型。
自動屬性
10,自動屬性:為了簡化簡單字段數據封裝的過程,C#3.0開始提供自動屬性語法,這個特性能讓我們使用新的語法為編譯器定義支持字段和相關的C#屬性。如果我們想要定義抽象屬性的話,還需要使用 abstract 關鍵字。注意:如果要定義自動屬性,就必須提供讀和寫兩個功能,我們不能構建只讀或只寫的自動屬性。示例:
class Car
{
public sting Name { get; protected set; };
}
擴展方法
11,C#3.0中,我們可以把方法定義為擴展方法。簡單地說,擴展方法允許現存已編譯的類型(如類,結構,接口)和當前即將被編譯的類型(如包含擴展方法的類型)在不需要被直接更新的情況下,獲得功能上的擴展。這樣通過擴展方法,我們可以為預編譯的類型(甚至我們并不擁有該類型的代碼)添加功能,同時這些方法將獨立分開存放。
12,使用擴展方法有一些限制:第一,擴展方法必須是靜態(tài)的;第二,所有的擴展方法都需要使用關鍵字 this 對第一個參數(并且僅對第一個參數)進行修飾;第三,每一個擴展方法只可以被內存中正確的實例調用,或者通過其所處的靜態(tài)類被調用。示例:該擴展允許所以System.Int32將自己的值倒置。
static class MyExtensions
{
public static int ReverseDigits(this int i)
{
char[] digits = i.ToString().ToCharArray();
Array.Reverse(digits);
string newDigits = new string(digits);
return int.Parse(newDigits);
}
}
13,在使用擴展方法的背后編譯器僅僅以普通的方式調用靜態(tài)方法,即把調用方法的變量作為調用參數(就是 this)。如上面的例子,編譯器會在背后轉換為 MyExtensions.ReverseDigits(aInt),因此我們可以使用普通C#語法像調用普通靜態(tài)方法那樣調用擴展方法。
14,由于擴展方法的靜態(tài)性,我們不能在擴展方法中直接訪問它擴展的類型的成員,但我們可以使用 this 來方法要擴展類型的所以公共成員(僅僅是公共成員)。
15,擴展方法的作用域:把包含擴展方法的靜態(tài)類型放到獨立的命名空間中后,處于同一程序集的其他命名空間可以使用標準的C#關鍵字 using 導入這些靜態(tài)類型和它們包含的擴展方法。需要牢記的是,如果沒有顯示地導入正確的命名空間,擴展方法對當前C#代碼文件是不可用的。
16,微軟推薦把擴展方法放在獨立的程序集(獨立的命名空間)-擴展庫,從而方便代碼的模塊化與管理。我們不僅可以擴展類還可以擴展接口。擴展接口稍微有點特別,我們擴展一個接口使其具有新成員的時候,必須提供這些成員的實現,這似乎已經脫離接口類型的本質(實際上是實現該接口的所以類型都具有靜態(tài)的新成員實現)。
分部方法(partial)
17,我們可以使用 partial 關鍵字來構建分部類定義,這樣我們可以跨多個代碼文件實現類型的語法,只有每一個分部類型具有同樣的完全限定名。在C#3.0起,我們可以把 partial 應用到方法級別,它允許我們在一個文件中構建方法原型,而在另一個文件中實現,但這樣做有許多限制。第一,分部方法只可以定義在分部類中;第二,分部方法必須返回 void;第三,分部方法可以是靜態(tài)或實例級別的;第四,分部方法可以有參數(包括被 this,ref或params修飾的參數,但不能具有 out 修飾符);第五,分部方法總是隱式私有的;第六,分部方法可能會放在已編譯的程序集中,也可能不會,因為編譯器會根據方法體是否實現來決定方法是否應該放到程序集中來,如果沒有方法體的話,所以方法的使用痕跡(調用,元數據描述以及原型)都會在編譯時去除。
18,由于分部方法必須是隱式私有的并總是返回 void,所以分部方法的用途并不大。通過用 partial 修飾符標記語法,其他類的構建者可以選擇提供實現細節(jié),這樣,分部方法就提供了比使用預處理指令更簡潔的方案,為虛方法提供了虛擬實現或拋出NotImplementException異常。此外使用分部方法來定義輕量級事件是很常見的,這使得類設計者可以提供方法掛鉤,就像事件處理程序一樣,開發(fā)人員可以選擇實現或不實現來決定是否需要響應某事件。根據命名約定,這樣的輕量級事件處理方法使用On前綴。
初始化
19,對象初始化器是以從左到右方式進行的。對于容器,我們可以使用集合初始化語法,此語法使我們可以像初始化普通數組一樣初始化容器。
匿名類型
20,匿名類型是匿名方法的自然延伸。當定義一個匿名類型,需要使用新的關鍵字 var 和前面介紹的對象初始化語法。比如:
static void Main(string[] args)
{
// 構建一個匿名對象表示一輛汽車
var myCar = new { Color = "White", Make = "Saab", CurrentSpeed = 60 };
Console.WriteLine(" >> My car is a {0} {1}.", myCar.Color, myCar.Make);
}
21,所有的匿名類型都自動繼承 System.Object,因此它們都支持基類的每一個成員,因此我們可以在其上調用 GetType(), ToString()等方法。匿名類的類型名完全由編譯器決定的,使用對象初始化語法定義的每一個名稱/值對分別被映射為擁有相同名字的屬性以及對應被該屬性封裝的私有數據成員。判斷匿名類型的對象相等(Equals())是基于值的語義,即比較兩個對象的每一個數據成員的值,但匿名類型并沒有重載C#的相等運算符(=和!=),因此相等運算符還是基于比較引用的。
22,匿名類型的用途:應該謹慎地使用匿名類型,尤其是使用 LINQ 技術時(快速構建一個實體而不需要定義其功能)。匿名類型有很多限制:第一,你不能控制匿名類型的名稱;第二,匿名類型繼承自 System.Object;第三,匿名類型不支持事件,自定義方法,自定義運算符和自定義重寫;第四,匿名類型是隱式封閉的(sealed);第五,匿名類型的實例創(chuàng)建只使用默認構造函數。
浙公網安備 33010602011771號