C#2.0語法上的變化:
①泛型:
爲什麼要引入泛型?
舉個例子比較好理解:例如定義一個System.Collection.ArrayList,裏面的元素是object類型的,當從中取出的時候需要作強制類型轉換ClassA tmp = myArrayList[0] as ClassA;這有兩方面問題,一是強制類型轉換的性能開銷,二是類型安全(編譯通過但是運行有可能出錯)。在.net1.0中類似的情況是比較多的,引入泛型是爲了較好地解決此問題。
所謂泛型,即通過參數化類型來實現在同一份代碼上操作多種數據類型。泛型編程是一種編程範式,它利用“參數化類型”將類型抽象化,從而實現更爲靈活的複用。
還是看看代碼吧:
class Stack<T>
{
private T[] store;
private int size;
public Stack()//構造函數
{
store = new T[10]; size=0;
}
public void Push(T tmp)
{
store[size++] = tmp;
}
public T Pop
{
return store[--size];
}
}
上面就是一個泛型的實現,在實例化的時候該類的時候我們可以這樣聲名
Stack<int> aaa = new Stack<int>();
那麼就約束了只能往這個堆棧裏放int類型,例如aaa.Push(17);是可以的;
但是aaa.Push("123");編譯就會不通過。
class C<U,V> {}
class D: C<string,int> {}
class E<U,V>: C<U, V> {}
class F<U,V>: C<string, int> {}
上面這些都是一些泛型的實現,這裏就不一一解釋了~
泛型還可以應用於接口和委託,實際編程時還有一些實際問題。
值得一提的是下面這個例子:(where)
class MyClass<S,T>
where S: A // S繼承自A
where T: B // T繼承自B
{......}
②匿名方法與迭代器;
匿名方法其實沒什麼,對比一下下面這兩段代碼就明白了:
(C# 1.0):
Button1.click += new EventHandler(Button1_Click);
private void Button1_Click(object sender,EventArgs e)
{
TextBox1.Text = "123";
}
有了匿名方法之後(C# 2.0):
Button1.Click += delegate {
TextBox1.Text = "123";
}
關於匿名方法,老實說,偶認爲只是爲了可以省掉幾行代碼,比較方便地處理委託,屬於C#編譯器的“小花招”而已......
然後是“迭代器”:
在沒有這個東東的時候如果需要創建一個集合(可用於foreach循環),需要如此實現
Public class MyCollection : Ienumerable {
public MYEnumerator GetEnumerator(){
return new MyEnumerator(this);
}
public class MyEnumerator : Ienumerator{
public void Reset(){ … }
public bool MoveNext(){ … }
public int Current{ … }
object IEnumerator.Current{ get{ … } }
}
}
有了“迭代器”之後,這樣就可以:
public class Stack<T>: IEnumerable<T>
{
T[] items;
int count;
public void Push(T data) {…}
public T Pop(){…}
public Ienumerator<T> GetEnumerator(){
for (int I = count – 1; i >=0;--i){
yield return items[i];
}
}
比較簡單,看看就能明白,有兩個地方稍有點新鮮的:
1)增加了yield關鍵字;
2)使用迭代器創建倒序遍歷:
Public Ienumerable<T> Bottom ToTop{
get {
for(int I = 0;i < count; i++>){
yield return items[i];
}
}}
③分部類型定義:
分部類型允許我們將一個類、結構或者接口分成幾個部分,分別實現在幾個不用的.cs文件中。當然,各個部分的命名空間是要相同的,訪問保護修飾符也不能互相沖突。
爲了實現這個東西,引入了半個關鍵字partial,之所以叫半個,是因爲只有和class、struct、interface放在一起時,纔有關鍵字的含義。
分部類型的實用意義偶倒是想到一個,就是我們有一些代碼文件是通過某些工具生成的(例如用一些映射工具或者自己寫的代碼生成工作,去生成一些基本的實體類、數據訪問類等),這些代碼文件我們又不希望跟手工增加的代碼放在一起,就可以分開n個部分來放。
最後來段簡單代碼作爲例子:
partial class MyClass
{
public void test1()
{....}
}
partial class MyClass
{
public void test2()
{....}
}
代碼可以這樣寫,最終編譯器還是會把各個部分編譯到一起的,沒有實質區別。
④Nullable 泛型結構:
Nullable 泛型結構允許一個值類型具有“空值”意義,從而方便很多場合的運算,如數據庫中的空字段。
int? a= null;
if(a == null)
{
// a如果爲空,則....;
}
else
{
// a如果不爲空,則....;
}
空屬類型實際上是一個泛型類型System.Nullable<T> 。
⑤靜態類:
問題真是一個比一個簡單,靜態類就是一個只包含靜態成員的類。
例子
static class MyStaticClass
{
public const int aaa;
public static void Test1()
{
//……
}
}
如果涉及到數據訪問,那麼還需要知道ado.net2.0的一些小變化:
①模型的調整:
例如在ado.net1.0裏,SqlConnection、OleDbConnection等,並沒有一個共同的基類,而是通過繼承接口 IDbConnection實現的,現在,則有了一個基類DbConnection,這可方便了一些,我們可針對基類編寫數據庫訪問的代碼,而不用關注具體的數據庫類型,有利於數據訪問層與數據庫的分離~
②關於DataSet(DataTable)的優化:
首先是新的索引引擎,看看例子:
DataTable dt = new DataTable();
dt.Columns.Add("field1");
dt.Columns.Add("field2");
dt.PrimaryKey = new DataColumn[] { dt.Columns[0] };//這句是關鍵,否則驗證不了
for (int i = 0; i < 200000; i++)
dt.Rows.Add(new object[] { i, DateTime.Now });
上面這段代碼在.net1.1執行需要40~50秒; 在.net2.0中運行在10秒左右
其次是真正的二進制序列化;
將上面這個包含有20萬條記錄的DataTable序列化成文件:
dt.RemotingFormat = SerializationFormat.Binary;//這個在.net1.1是沒有的
System.Runtime.Serialization.Formatters.Binary.BinaryFormatter bf = new System.Runtime.Serialization.Formatters.Binary.BinaryFormatter();
System.IO.FileStream fs = new System.IO.FileStream(@"D:/test1.txt", System.IO.FileMode.CreateNew);
bf.Serialize(fs, dt);
fs.Close();
.net1.1得到的是一個大小約29M的文件;.net2.0得到的是約7M的文件;用記事本打開看看就知道差別在哪裏。
在使用Remoting傳送DataSet或者DataTable對象的時候,這是一件好事。
最後,在ado.net2.0中,DataTable更獨立了,不像過去那樣特別依賴DataSet,有時候不得不把DataTable放到DataSet中僅僅是爲了獲得某項功能,例如ReadXML()、 WriteXMlSchema()等。
③針對MS SQL Server,特別是MS SQL Server2005所作的一些優化:
這有幾方面話題,一是異步處理
System.Data.SqlClient.SqlCommand cm = new SqlCommand("async=true;.....");
System.IAsyncResult ar = cm.BeginExecuteReader();
//.....
//do other processing
System.Data.SqlClient.SqlDataReader dr = cm.EndExecuteReader(ar);
二是大批量數據操作的優化
System.Data.SqlClient.SqlBulkCopy bcp = new SqlBulkCopy("連接字符串");
bcp.WriteToServer(myDataTable);
三是在ADO.NET 2.0針對Sql Server 2005可以同時在Command對象上打開多個DataReader