讀書筆記之《C#入門經典》基礎篇
總結一些在學習《C#入門經典》一書中的技巧細節以及基礎知識點,由於本人是一個objective-c程式設計師,所以會偶爾碰到C#與objectiv-c比較類似的概念會提醒一下,下面是基礎篇:1.主動進行垃圾回收檢查。.NET垃圾回收會定期檢查計算機記憶體,從中刪除不再需要的內容。這種檢查不定時,因此需要許多記憶體才能執行的程式碼應該自己執行這樣的檢查,而不是坐等垃圾回收。
2.C#程式碼是區分大小寫的,必須使用正確的大小寫形式輸入程式碼。
Debug.Log("C# Programming!"); //正確的大小寫字母 DEBUG.LOG("C# Programming!");//錯誤,不能通過編譯 Debug.log("C# programming!"); //錯誤的大小寫形式,不能通過編譯
3.#region和#endregion關鍵字,使用來定義可以展開和摺疊的程式碼區域的開頭和結尾。這有點類似與Objective-C裡的#pragma mark 可以給程式碼劃分段落,提高程式碼的可讀性。
#region define datas
int a = 10,b = 100;
string userName = "user0";
#endregion
4.checked和unchecked關鍵字,用來檢查表示式的上下文是否溢位。
byte destVar; short sourceVar = 281; destVar = (byte)sourceVar; Debug.Log("sourceVar = " + sourceVar); Debug.Log("destVar = " + destVar); // 列印結果如下:sourceVar = 281 destVar = 25 為什麼呢?因為byte可儲存的最大值是255.使用checked關鍵字可以避免類似的問題。 byte destVar; short sourceVar = 281; destVar = checked((byte)sourceVar); Debug.Log("sourceVar = " + sourceVar); Debug.Log("destVar = " + destVar); //執行這段程式碼,程式會崩潰並顯示錯誤資訊4.checked和unchecked關鍵字,用來檢查表示式的上下文是否溢位。
5.使用Convert命令進行顯示轉換。比如:Convert.ToDouble(var);如果不能轉換,編譯器會告訴使用者。
6.使用ref關鍵字指定引數來實現引用傳遞引數,通過引用引數可以實現改變用作引數的多個變數值,解決函式只能返回一個返回值的侷限性。
static void PowNum(ref int var) {
var = var * var;
}
//使用還必須指定ref引數
int number = 8;
PowNum(ref number);
//注意,用作ref引數的變數有兩個限制。1、函式可能會改變引用引數的值,必須在函式呼叫中使用“非常量”變數。2、必須使用初始化過的變數。C#不允許ref引數在使用他的函式中初始化。比如下面的用法是錯誤的
錯誤用法1:
const int number = 8;
PowNum(ref number);
錯誤用法2:
int number;
PowNum(ref number);
7.out關鍵字也可以實現傳遞值,指定所給的引數是一個輸出引數,使用方式與ref關鍵字相同。但是存在一些區別:把未賦值的變數用作ref引數是非法的,但可以把未賦值的變數用作out引數;另外,函式使用out引數時,out引數必須看作未賦值。
static void PowNum(out int var) {
var = 10;
var = var * var;
}
int var;
PowNum(out var);
//此時var值為100
8.結構函式;
struct UserInfo {
pubilc string firstName, lastName;
public string UserName () {
return firstName + lastName;
}
}
9.委託是一種可以把引用儲存為函式的型別。委託的宣告非常類似於函式,但不帶函式體,且要使用delegate關鍵字。見例子:
class Demo {
delegate double HandleNumberDelegate (double num1, double num2);
static double Add(double num1, double num2) {
return num1+ num2;
}
static double substract (double num1, double num2) {
return num1 - num2;
}
static void Main() {
HandleNumberDelegate handleNumDelegate;
double num1 = 100, num2 = 40;
string input = Console.ReadLine();
if ("A" == input)
handleNumDelegate = new handleNumberDelegate(Add); //這是委託賦值的一個獨特語法,可以直接寫成handleNumDelegate = Add;
else
handleNumDelegate = new handleNumberDelegate(substract);
Debug.Log("HandleNum Res = " + handleNumDelegate(num1,num2));
}
}
10.除錯列印函式
//1.非中斷模式的列印函式
Console.WriteLine()
Debug.WriteLine() //釋出版本不會編譯這個語句
Trace.WriteLine() //釋出版本也可以列印
Console.Write()
Debug.Write()
Trace.Write()
Debug.WriteLineIf()
Trace.WriteLineIf()
Debug.WriteIf()
Trace.WriteIf()
//2,中斷模式的列印函式
Debug.Assert(null != var, "var is null","Assertion occurred in main()");
Trace.Assert()
11.錯誤處理
try {
.... //包含丟擲異常的程式碼
}
catch (<exceptionType> e) {
... //包含要丟擲異常要執行的程式碼,可以提供多個catch塊,<exceptionType> 設定為只響應特定的異常型別(如:System.IndexOutOfRangeException)。還可以忽略這引數,響應所有的異常
}
finally {
...//包含總是會執行的程式碼,如果沒有異常,則在try塊之後執行;如果處理了異常,則在catch塊之後執行
}
12.介面是把公共例項方法和屬性組合起來,以封裝特定功能的一個集合。注意,介面不能單獨存在,不能例項化,不能包含實現其成員的任何程式碼,實現過程必須在實現介面的類中完成。介面也是可以繼承的。介面成員的定義與類成員的定義類似,但有幾個重要的區別:
不允許使用訪問修飾符(public、private、protected 或 internal),所有的介面成員都是公共的。
介面成員不能包含程式碼體。
介面不能定義欄位成員。
介面成員不能用關鍵字static、virtual、abstract、sealed來定義。
型別定義成員是禁止的。
實現介面的類必須包含該介面所有成員的實現程式碼。而且必須匹配指定的簽名(包括匹配指定的get和set塊),並且必須是公共的。可以使用virtual或abstract來實現介面成員,但不能使用static或const。
隱式實現的介面成員可以通過類和介面訪問,而顯式實現的介面成員只能通過介面訪問。
如果在定義屬性的介面中只包含set塊,就可以給類中的屬性新增get塊,反之亦然。但是隻有所新增的存取器的可訪問修飾符比介面中定義的存取器的可訪問修飾符更嚴格時,才能這麼做。
public interface IBaseInterface {
int GIntProperty {
get;
}
void DoSomething ();
void DoSometingElse ();
}
public class BaseClass {
public virtual void DoSomethimg () {
}
}
public class DerivedClass:BaseClass, IBaseInterface {
public int GIntProperty {get; protected set;}
public void IBaseInterface.DoSomethingElse () { //顯示實現介面,不能通過類的例項來訪問,
}
}
DerivedClass derivedObj = new DerivedClass ();
IBaseInterface baseInterface = derivedObj;
baseInterface.DoSomethingElse ();
13.關於C#類的修飾符關鍵字:public class MyClass { // class members } ,默認情況下,類宣告為內部的,預設為internal訪問修飾符關鍵字修飾,只能在當前的專案中的程式碼才能訪問它。而用public顯式指定類是公共的,可以被其他專案訪問。編譯器不允許派生類的可訪問性高於基類,也就是internal類可以繼承於一個public類,但一個public類不能繼承於一個內部類。
可以用abstract或sealed來修飾類,其中abstract關鍵字指定類是抽象的,不能被例項化,只能繼承,可以有抽象成員,sealed關鍵字指定類是密封的,不能被繼承。比如:public abstract class MyClass { //類成員}
可以在類中指定繼承和介面。基類只能有一個,但是介面可以指定多個。如果指定了基類,它必須緊跟在冒號的後面,之後才是指定的介面。如果沒有指定基類,則介面就跟在冒號的後面。必須使用逗號分隔基類名和介面名。例子:public class MyClass:MyBase,IMyInterface,ISecInterface { // 類成員}
base關鍵字在C#裡邊有點類似與objective-c類裡的super的概念,就是表示基類的物件例項。this關鍵字在c#裡邊類似objective-c類裡的self概念,表示當前類的物件例項自身。
14.定義類成員的訪問級別關鍵字:
public-----成員可以由任何程式碼訪問,
private------成員只能由類中的程式碼訪問(如果沒有任何關鍵字,C#語言預設使用這個關鍵字,PS:貌似各個語言的預設關鍵字不一樣的,比如objective-c語言的類成員的預設關鍵字是protected)
internal--------成員只能由定義它的程式集(專案)內部的程式碼訪問
protected----------成員只能由類或派生類中的程式碼訪問。PS:protected internal組合使用表示類成員只能由程式集中的派生類的程式碼來訪問。
readonly--------表示類成員只能在執行建構函式的過程中賦值,或有初始化賦值語句賦值。
static-------定義類成員為靜態,必須通過他們的類來訪問,比如:Class.ClassIntMember.而不是通過這個類的例項來訪問
const-----定義類成員為不可以修改,也是靜態的。
15.定義類方法的關鍵字:
static------同類成員一樣,靜態的方法只能通過類來訪問,不能通過物件例項來訪問。
virtual-------虛擬函式,方法可以重寫。
abstract------方法必須在非抽象的派生類中重寫(只用於抽象類中)
override-----方法重寫了一個基類方法(如果方法被重寫,必須使用該關鍵字)。如果使用了override,還可以使用sealed指定在派生類中不能對這方法做進一步的修改,即這個方法不能由派生類重寫
extern-------方法定義放在其他地方,可以在專案外部提供方法的實現程式碼。
例子:
public class MyClass:BaseClass {
public override sealed void DoSomething () {
//
}
}
16.定義屬性,屬性擁有兩個類似於函式的塊,一個塊用於獲取屬性的值,另一個用於設定屬性的值,分別稱為get訪問器和set訪問器。每個訪問器也可以有自己的可訪問性,但是訪問器的訪問性不能高於它所屬的屬性,私有屬性的訪問器不能包含任何可訪問修飾符。屬性可以使用virtual、override、abstract關鍵字,就像方法一樣。
public class MyClass {
private int gInt;
public int GInt {
get {
return gInt;
}
protected set {
gInt = value;
}
}
}
17.隱藏基類方法。使用new關鍵字可以顯示地在派生類中隱藏基類的方法。
public class BaseClass {
public void DoSomethimg () {
Debug.Log("In Base");
}
}
public class DerivedClass:BaseClass {
new public void DoSomething () {
Debug.Log("In Derived");
}}
DerivedClass derivedObj = new DerivedClass();
BaseClass baseObj;
baseObj = derivedObj;
baseObj.DoSomething ();
//列印結果:In Base
注意隱藏基類成員和重寫它們的區別。重寫方法是將替換基類中的實現程式碼,即使是通過基類型別進行訪問,也仍然是呼叫派生類的方法(多型性)。但是new關鍵字隱藏基類的實現程式碼,仍然可以通過基類訪問它。
public class BaseClass {
public virtual void DoSomethimg () {
Debug.Log("In Base");
}
}
public class DerivedClass:BaseClass {
public override void DoSomething () {
Debug.Log("In Derived");
}
}
DerivedClass derivedObj = new DerivedClass();
BaseClass baseObj;
baseObj = derivedObj;
baseObj.DoSomething ();
//列印結果:In Derived
無論是重寫成員還是隱藏成員,都可在派生類中訪問基類成員。要對派生類的使用者隱藏繼承的公共成員,但仍能在類中訪問其功能。要給繼承的虛擬成員新增實現程式碼,而不是簡單地用重寫的新程式碼替換它。要實現以上目的,可以使用base關鍵字,可以包含在派生類中的基類實現程式碼。
public class BaseClass {
public virtual void DoSomethimg () {
//基類的實現
Debug.Log("In Base");
}
}
public class DerivedClass:BaseClass {
public override void DoSomething () {
base.DoSometing(); //是不是很類似objective-c中的super?
//派生類的實現程式碼
Debug.Log("In Derived");
}
}
對於介面,同樣也可以用關鍵字new來隱藏基介面的成員。
interface IBaseInterface {
void DoSomething ();
}
Interface IDerivedInterface : IBaseInterface {
new void DoSomething () ;
}
18.部分類定義,使用partial關鍵字來定義部分類,將類的定義放在多個檔案中。例如:屬性、欄位放在一個檔案中,而方法放在另一個檔案中。只需要在每個包含部分類定義的檔案中對類使用關鍵字partial即可。應用與部分類的介面也會應用於整個類。部分類也可以定義部分方法,但沒有方法體,在另一個部分類中包含實現程式碼。部分類定義可以在一個部分類定義檔案或多個部分類定義檔案中包含基類。但是如果基類在多個定義檔案中指定,它就必須是同一個基類。
public partial class MyClass :BaseClass {
partial void DoSomething ();
}
public partial class MyClass: BaseClass {
partial void DoSomething () {
Debug.Log("In DoSomething");
}
}
注意,部分方法可以是靜態的,但它們總是私有的,而且不能有返回值。它們使用的任何引數都不能是out引數,但可以是ref引數。部分方法也不能使用virtual、abstract、override、new、 sealed、extern修飾符。
19.集合。C#中的System.Collections名稱空間的幾個介面提供了基本的集合功能:
IEnumerable可以迭代集合中的項。
ICollection(繼承於IEnumerable)獲取集合中項的個數,並把項複製到一個簡單的陣列型別中。
IList(繼承於IEnumerable和ICollection)提供了集合的項列表,允許訪問這些項,並提供其他一些與項列表相關的基本功能。
IDictionary(繼承於IEnumerable和ICollection)類似於IList,但提供了可通過鍵值(而不是索引)訪問的項列表。
其中System.Collections.ArrayList是一個可變陣列。簡要介紹其一些方法,具體可MSDN的官方文件。可以通過索引訪問其成員,Add()方法新增新項;可以使用foreach函式遍歷數組成員;Count屬性獲取陣列個數; Remove()和RemoveAt()方法刪除項,AddRange()方法一次新增好幾個項,IndexOf()方法獲取物件在陣列中的索引。
20。型別比較,GetType方法,所有的類都從System.Object中繼承了這個方法,這個方法和typeof()運算子一起使用,就可以確定物件的型別。
if (myObj.GetType() == typeof(MyClass)) {
//myObj是MyClass類的一個例項
}
封箱和拆箱,封箱就是將值型別轉換為System.Object型別,或者轉換為由值型別實現的介面型別。拆箱則是相反的轉換過程。
is運算子,可以檢查物件是否是給定型別或者是否可以轉化為給定型別,如果是,這個運算子就返回true。
if (myObj is MyClass) {
//myObj 是MyClass類的一個例項
}
21.型別轉換。as運算子可以把一種型別轉換為指定的引用型別,如果不能轉換,表示式的值就是null。
class ClassA {
// ....
}
class ClassB : ClassA {
//...
}
ClassA obj1 = new ClassA ();
ClassD obj2 = obj1 as ClassD; //obj2 是null