本文章不適合入門,只適合有一定基礎的人看。我更相信知識細節見高低,我是從4.0開始學的,終於有時間系統的學習C#5.0,是5.0中的知識,會特殊標記下。但寫的內容也可能含有其他版本framework的知識,也是為了方便自己更好的記憶C#知識。文章內容都是自己總結,無抄襲,如果你覺得文章檔次太低,請大牛繞道 --Aaronyang的博客(www.ayjs.net)
1. 泛型-是C#的泛型
1.1 性能方面比非泛型好點,比如拆箱裝箱的問題。個人感覺代碼可讀性更好吧。還有就是 寫代碼可能可以寫出很精彩的代碼。命名用T開頭,加有意義的單詞,比如 Converter<TInput,TOut>,XX<TKey,TValue>
1.2 題目:不百度,請自己至少列舉5個 例如List<T>使用泛型的C#中的常用對象
1.3 自己寫個鏈式,並使用泛型知識的demo
1.定義鏈式節點, 前一個節點,后一個節點,再加上自己這個節點就OK了
//定義鏈式節點, 前一個節點,后一個節點,再加上自己這個節點就OK了 public class MyLinkedNode<T> { public MyLinkedNode(T value){ this.Value = value; } public T Value{get;private set;} /// <summary> /// 前一個節點對象 /// </summary> public MyLinkedNode<T> Prev { get; internal set; } /// <summary> /// 后一個節點對象 /// </summary> public MyLinkedNode<T> Next { get; internal set; } }
2.接下來,在封裝一個對節點的操作的操作類,正好復習 迭代器yield和理解IEnumerable<T>這個接口,時間有限,這里我只先實現AddLast和GetEnumerator
//接下來,因為鏈式結構,只適合從尾部和首部增加元素,中間不方便增加元素。所以對節點的操作的封裝類,一般 首部增加一個節點AddFirst(),尾部增加一個節點AddEnd() //移除一個節點RemoveFirst(),RemoveEnd(),這里我只先實現AddEnd和GetEnumerator public class MyLinkedList<T> : IEnumerable<T> { /// <summary> /// 默認 IEnumerable定義的,必須實現 /// </summary> /// <returns></returns> public IEnumerator<T> GetEnumerator() { //使用yield,把MyLinkedNode<T>返回到IEnumerator中去 MyLinkedNode<T> cur = First; while (cur!=null) //如果下一個節點不為空 { yield return cur.Value; cur = cur.Next;//把當前值設置成下一個節點的值 } } System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator() { return GetEnumerator(); } /// <summary> /// 添加一個節點,默認都是從尾部增加的 /// </summary> /// <param name="myLinkedNode">MyLinkedNode中類型的值</param> /// <returns></returns> public MyLinkedNode<T> AddEnd(T myLinkedNode) { MyLinkedNode<T> cur = new MyLinkedNode<T>(myLinkedNode); if (First == null) { //如果該集合一個節點也沒有,那么第一個和最后一個節點就等於當前節點 First = End = cur; } else { //因為尾部新節點增加,原來上次的尾部的節點就變成了該節點的前一個節點了,他自己變成了最后一個節點 MyLinkedNode<T> prevEnd = End; //更新新的最后一個元素 End.Prev = prevEnd; End.Next = cur; End = cur; } return cur; } //在鏈式結構里面都有 第一個節點和最后一個節點的特殊節點 /// <summary> /// MyLinkedList集合中第一個元素 /// </summary> public MyLinkedNode<T> First { get; private set; } /// <summary> /// MyLinkedList集合中最后一個元素 /// </summary> public MyLinkedNode<T> End { get; private set; } /// <summary> /// 在開始的地方增加一個節點 /// </summary> /// <param name="myLinkedNode">MyLinkedNode值</param> /// <returns></returns> public MyLinkedNode<T> AddFirst(T myLinkedNode) { throw new NotImplementedException();//自己實現 } /// <summary> /// 移除一個節點 /// </summary> /// <param name="myLinkedNode">MyLinkedNode對象</param> /// <returns></returns> public MyLinkedNode<T> RemoveEnd(T myLinkedNode) { throw new NotImplementedException();//自己實現 } }
3.使用這個數據結構的集合
class Program { static void Main(string[] args) { MyLinkedList<int> m = new MyLinkedList<int>(); m.AddEnd(1); m.AddEnd(10); m.AddEnd(100); foreach (var item in m) { Console.WriteLine(item+","); } Console.ReadLine(); } }
效果
整個過程來說,感覺還是挺有意義的,特別當泛型的概念融入其中,你的代碼可能更精彩。
1.4 一些數據結構的類型,只是加深印象: Queue<T>,Dictionary<TKey, TValue>, ILookup(TKey, TElement) 等
1.5 泛型默認值初始化,舉個例子 public T GetT(){ T t=default(T); ... }
1.6 泛型約束與繼承:
public abstract class Class1<T> :TEnumerable<T>
public class DBManager<TDb> where TDb:ICommonDb,new()
Aaronyang拓展: where T:struct / class / 接口 / new() 構造函數約束,指定類型T必須有一個默認構造函數 / 其他泛型,例如 where T1:T2
*1.7 靜態成員:AaronYang講解:只要記得 T 不一樣,里面的靜態成員的值是不共享的,也不會受影響。 專業術語:泛型類的靜態成員只能在類的一個實例中共享
自己寫了一個例子,一看就懂了
class Program { static void Main(string[] args) { OwnStaticGeneric1<string>.obj = 4; OwnStaticGeneric1<int>.obj = 5; OwnStaticGeneric1<string>.obj = 6; OwnStaticGeneric1<int>.obj = 7; Console.WriteLine(OwnStaticGeneric1<string>.obj);// =>6 Console.WriteLine(OwnStaticGeneric1<int>.obj); // =>7 OwnStaticGeneric2<string>.obj = "4"; OwnStaticGeneric2<int>.obj = 5; OwnStaticGeneric2<string>.obj = "6"; OwnStaticGeneric2<int>.obj = 7; Console.WriteLine(OwnStaticGeneric1<string>.obj);// =>6 Console.WriteLine(OwnStaticGeneric1<int>.obj); // =>7 Console.ReadLine(); } } public class OwnStaticGeneric1<T> { public static int obj; } public class OwnStaticGeneric2<T> { public static T obj; }
1.8 高級知識: 泛型接口,感覺讓你考架構師的樣子
1.8.1 拓展一下 可能會使用的 跟 ref和out差不多性質的 in(in修飾的參數,在方法體內的過程不會改寫in的參數的值)關鍵字用法。如果不太懂,可以百度,也可以看我下面的例子,但提前,你最好懂out,ref的基礎用法。
有些人設計接口直接 IInterface<T1,T2>,其實也還有很奇妙的其他寫法,用 in或者out或者ref 修飾泛型的場景
講解: 一個SubClass類實現了ITestIn接口,out定義輸出類型,in定義輸入類型,必須是把值輸入,所以莫名的 ITestIn<string,object> 一下子就懂了。還不懂的話,建議你百度
留個題目:如何 讓用戶寫代碼可以寫出如下的效果,Student的值是不允許改變的,請設計接口
public class Student:ICustomComparable<Student>{
public int CompareTo(Student stu){
return ... ;
}
}
參考部分答案(答案字體被我設置成白色了,查看的,自己選擇后面的空白部分): public interface ICustomComparable<in T>{ int CompareTo(T stu); }
1.8.2 其實上面的 in或者out修飾泛型,涉及到了泛型知識中的 協變(泛型參數被out修飾)與抗變(泛型參數被in修飾)的知識,不要太在意,會用就好!!!!!!oh! shit,抗英(國)
1.9 Nullable<T> T必須是值類型,定義可為空,有興趣的可以看看 public struct Nullable<T> where T:struct的實現
等同寫法: Nullable<int> a 等同於 int? a
?? 的用法: 例如 int y=x ?? 0; 如果x為null,則等於0,否則就是原值。
1.10 當然泛型也可以像用在類上那樣用於方法上,這個知識太簡單,不講了
1.11 泛型委托,Lambda表達式最多,典型的有比如Func Action等,這些在LINQ里再講
1.12 作為一年以上的開發人員,都知道的我都跳過了,可能存在疑問的地方保留了。
======安徽六安=========www.ayjs.net==========aaronyang========楊洋==================