一、C#程序是一組類型聲明。
(C程序時一組函數和數據類型,C++程序時一組函數和類)
這裏的類型是指type,包括:(1)預定義類型:int、bool、string 等;(2)用戶定義類型:類類型(class)、結構(struct)、數組(ARRAY)、枚舉(enum)、委託(delegate)、接口(interface)、泛型。
類型通過類型聲明創建,包含:
(1)要創建的類型的種類;(2)新類型的名稱;(3)對類型中每個成員的聲明(名稱和規格)。array和delegete類型除外,他們不含有命名成員。
一旦聲明瞭類型,就像他們是預定義類型一樣。
2、聲明類類型的變量所分配的內存是用來保存引用的(保存在棧裏),而不是用來保存類對象實際數據的。要爲實際數據分配內存,需要使用new運算符。如: myclass mc=new myclass();在這裏面,myclass mc是聲明,而new myclass()是初始化;同樣,int i=2 中,int i 是聲明,=2是初始化。
二、var關鍵字。
var關鍵字只能用在本地變量,即只能用在某個方法、函數內部。(不能用在類裏的字段)
只能在變量聲明中包含初始化時使用。因爲.net可以根據後面的初始化內容推斷出var的類型,如果後面沒有初始化,是不行的。
一旦推斷出類型,就固定不能更改了,它仍然是強類型性質。
.NET的關鍵字var和JAVASCRIPT中的var是不一樣的,js可以引用不同的類型。
三、堆棧
棧,是一個內存數組,是後進先出的數據結構。堆:是一塊內存區域,在堆裏可以分配大塊的內存用於存儲某種類型的數據。
值類型,數據存放在棧裏;引用類型:第一段是一個引用,指向數據在堆裏的存放位置,第二段是存儲實際的數據,它總是在堆裏。
值類型有:
(1)預定義類型:byte/int/long/bool等,僅僅除了:object和string。
(2)自定義類型:struct/enum。除了:class/interface/delegate/array。
所以,對於一個方法,如: void myfun(myclass f1,int f2){f1.hisInt+=1;f2+=1;} ,最終,因爲參數是變量的複製,一個是引用,一個是值類型,對於值類型,其內的改變並不影響外面的字段;而引用類型的myclass.hisInt因爲是引用類型,所以其外面的堆裏的值會被改變。
四、屬性
屬性表面上和類中的“字段”很相似,都是類成員、都有類型、都可以被賦值和讀取。
但,屬性是一個函數成員,它不爲數據存儲分配內存!它執行代碼。
屬性是指定的一組兩個匹配、成爲訪問器的方法(get/set)。
只有get訪問器的,叫只讀屬性,只有set訪問器的,叫只寫屬性,但他們至少有一個必須定義。
五、委託和事件
(一)、委託是類型,他包含具有相同簽名和返回值類型的有序方法列表。當他被調用時,他調用列表中的每一個方法。
如:
delegate void myDel(int x);
myDel delVar1=new myDel(myobj.myM1);
myDel delVar2=myobj.myM2; //上面和這行的意思一樣,只是這行省略了new
myDel delVar3=delVar1 + delVar2; //或者 delVar1 +=myobj.myM2;
這裏,如果執行: delVar1(5),就相當於執行了:myobj.myM1(5);myobj.myM2(5);
(二)、事件不是類型,是成員,所以:
A、由於不是類型,所以不能用new表達式來創建他的對象。
B、由於是成員,所以必須聲明在類或結構中,且不能再一段可執行代碼中聲明對象。
C、事件成員被隱式自動初始化爲null。
可以說:事件就是一個封裝了的委託,是一個委託類型的變量。
事件聲明需要委託類型的名字,如:
class MyTimerClass
{ public event EventHandler myEve; }
其中委託類型的名字可以是自定義的,也可以是.NET BCL預定義的委託類型,建議使用EventHandler,他當時的定義是:
public delegate void EventHandler(object sender,EventArgs e);
其中第一個參數:object sender用來保存觸發事件的對象的引用;由於是object,所以可以匹配任何類型的實例。
第二個參數用來保存有關狀態對應用程序來說是否合適的狀態信息。
但實際上,EventArgs類被設計爲不能傳遞任何參數。他用於不需要傳遞數據的事件處理程序--通常會被忽略。
如果希望傳遞數據,必須聲明一個從EventArgs類繼承的類,使用合適的字段來保存需要傳遞的數據。譬如:
注:類有9種成員:函數成員:方法、屬性、事件、構造函數、Finalizer方法、運算符、索引;數據成員:字段、常量。
其中,能被外界經常看到或引用的是前3種。 所以事件是封裝的委託類的變量。
六、接口 (含枚舉和LINQ的一些知識)
1、接口表示一組函數成員而不實現成員的引用類型,包含以下函數成員的聲明:方法、屬性、事件、索引。BCL中內置了一個IComparable的接口,如下:
public interface IComparable
{ int CompareTo(object obj); }
知道靜態方法:Array.Sort(數組)爲何可以排序數字、英文、或者漢字嗎?因爲它會調用這個數組中按IComparable接口要求實現的CompareTo方法,如果是則可以排序,如果不是就沒有辦法進行排序。
注:接口是引用類型,所以可以通過把類對象引用強制轉換爲接口類型來獲取指向接口的引用,一旦有了接口的引用,就可以使用點號來調用接口的方法。如:Imy imy=(Imy)mc;
2、foreach爲何可以列舉出其內的所有內容,爲何這麼神奇?
原因是數組可以按需提供一個叫做枚舉數(enumerator)的對象,對於有枚舉數的類型而言,必須有一個方法來獲取他們。在.NET中獲取一個對象枚舉數的標準方法就是調用對象的GetEnumerator方法。實現GetEnumerator方法的類型叫做可枚舉類型(enumerable)。數組就是可枚舉類型。
(1)IEnumerator接口。他包含三個函數成員:Current屬性、MoveNext和Reset方法。
(2)IEnumerable接口。僅有一個成員:GetEnumerator方法。
(3)泛型IEnumerable<T>接口。它也包含了一個方法:GetEnumerator方法。然而這個版本的GetEnumeratorfanui實現泛型IEnumerator<T>接口的類對象;由於類必須實現兩個GetEnumerator方法,我們需要顯示實現非泛型版本,並在類中實現泛型版本。
總之,正因爲有了I..or接口的三個成員,所以foreach纔可以得以循環列出其內容。
可枚舉類型可通過迭代器來進行創建。如:
3、LINQ
LINQ查詢結果實際是IEnumerable<>,如:
IEnumerable<int> lowNums= from n in numbers select n;
Linq查詢可以返回2種類型的結果:枚舉(IEnumerable)和標量(scalar),如:
int numsCounts=(from n in numbers select n).Count(); //返回一個整數。
理解查詢變量的內容很重要。在執行了以上代碼後,lowNums不會包含查詢的結果,因爲它包含的是IEnumerable<int>類型的對象(也可用var來讓計算機識別並代替),是引用類型,放在棧裏的是lowNums,他引用的結果是放在堆裏面的 IEnumerable<int> 再指向同是堆裏面的其他枚舉數。所以,查詢表達式返回枚舉,查詢一直到處理枚舉時纔會被執行。如果枚舉被處理多次,查詢就會被執行多次。
而,如果查詢表達式返回標量,查詢會立即執行,並把結果保存在查詢變量中,即棧中。
4、C#事件與FLEX事件
我認爲:C#中的: btn.Click +=btn_click;
等價於FLEX中的:btn.addEventListener(MouseEvent.CLICK,"btn_click");