[AaronYang]C#人愛學不學[4]


本文章不適合入門,只適合有一定基礎的人看。我更相信知識細節見高低,我是從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========楊洋==================

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM