1. 程式人生 > >一個demo學會c#

一個demo學會c#

全棧工程師開發手冊 (作者:欒鵬)

學習了c#4.5高階程式設計這本書,自己喜歡邊學邊總結邊寫demo,所以寫了這篇文章,包含了大部分的c#程式設計知識。讓你一個demo掌握c#程式設計,如果有問題可以留言。
此demo主要包括五個檔案:Students.cs和Moniter.cs檔案,包含了自定義空間、空間函式、空間變數、空間自定義類;Interface1.cs檔案和Interface2.cs檔案為介面檔案;index.cs檔案為主程式運算。

Students.cs和Moniter.cs檔案包含了自定義基、繼承類、模板類的定義及實現。涉及到自定義類的建構函式、過載建構函式、函式預設值、解構函式、複製建構函式、過載運算子(賦值函式、加法函式)、虛擬函式、常值函式、靜態函式、靜態變數、常值變數、列舉變數、內部類、訪問修飾符、繼承、重寫虛擬函式、基類引用、不定引數函式、友函式、友類、型別引用、終態函式、終態類、模板變數等內容。

Students.cs檔案內容如下:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace csharpdemo
{
    //自定義結構體,值型別
    struct People
    {
        string name;
        int id;
    }
    //static int vartemp=10;    //禁止使用脫離類的全域性資料
    //自定義類,引用型別。一個檔案可以包含多個類,類預設為修飾符為私有
public class Student : IComparable<Student> { public static void main(String[] args) { } //每個類中都可以有一個main函式,用於除錯 static Student() { default_name = "student"; } //靜態建構函式,在第一次呼叫類的任何成員之前,僅執行一次,不能有引數,不用訪問修飾符,且只有有一個
public Student() //自定義無參構造器,沒有自定義構造器時,編譯器會生成預設無參構造器, : this("student", 12) //通過this僅能呼叫一個構造器,必須將構造器呼叫置於起始處 { getname(); Console.WriteLine("基類無參構造器建立了一個物件"); } public Student(string name,int age){ //有參構造器,設定int age=12為預設值,可單引數呼叫 this.age = age; this.name = name; Console.WriteLine("基類有參構造器建立了一個物件"); } public Student(string name,params object[] args) //可變引數列表,args是一個引數列表,過載方法中應該只有一個使用可變引數列表,且位於引數的最後面,編譯器會自動呼叫最符合的過載函式執行 { this.name = name; Console.WriteLine("基類變參構造器開闢了一個物件"); //args[0]為變參中的第一個引數 } ~Student() { Console.WriteLine("基類解構函式"); } //解構函式 public static Student operator +(Student student1, Student student2) //運算子過載 +號運算 可以過載多種運算。 { Student student = new Student(student1.name+student2.name); return student; } public static Student operator +(Student student1, string name2) //運算子過載,為避免過載時的隱式轉化,+必須位於student變數的後面 { Student student = new Student(student1.name + name2); return student; } public void setname(string name) { Console.WriteLine("基類設定名稱" + name); this.name = name; } //this表示對當前物件的引用 public virtual string getname() { Console.WriteLine("基類獲取名稱" + name); return name; } //使用public方法實現對private資料的控制,保證類內資料安全 public string tast { get; private set; } //自動實現屬性訪問設定器 internal void setage (ref int age){Console.WriteLine("基類設定年齡"+age);this.age=age;} //ref傳遞引用 public virtual void getage(out int age){age=this.age;} //out對未初始化的變數進行保留改變,virtual虛擬函式不能私有 internal static long time = 10; //資料均可在定義時初始化,internal引用當前類的所有類可見 private int age = 0; //private外部不可以訪問 public string name = "student"; static string default_name; public const int default_age = 12; //const定義常量,定義時賦值,不能是static public Sextype sextype = new Sextype(); //訪問內部類,編譯器自動生成構造器 public enum allsex { man, woman } //列舉型別,等價於類內組合class allsex{man,woman} public class Sextype //內部類,無法通過內部類返回外部類的引用,當內部類宣告為static時為巢狀類,巢狀類不屬於物件,而屬於類名 { public void setsex(allsex sextype) { switch (sextype) { case allsex.man: sexstring = "man"; break; case allsex.woman: sexstring = "woman"; break; default:break; } } private string sexstring; } //重寫equals虛擬函式,重寫equals必須重寫gethashcode否則發生警告 public override bool Equals(object another) { Console.WriteLine("比較了兩個基類"); if (this.age == ((Student)another).age && this.name == ((Student)another).name) return true; return false; } //重寫雜湊函式 public override int GetHashCode() { return base.GetHashCode(); //呼叫基類的雜湊函式 } //實現比較函式 public int CompareTo(Student arg0) //要實現排序,必須要實現比較介面 { return age < arg0.age ? -1 : (age == arg0.age ? 0 : 1); //返回-1表示小於,0表示等於,1表示大於 } } //一個檔案可以包含多個類, abstract class Teacher //abstract宣告抽象類或抽象函式 { public abstract void setname(); //abstract抽象方法 public string getname() { return name;} //使用public方法實現對private資料的控制 string name = "teacher"; //不加修飾符預設為? } sealed class president<T> : Teacher //派生類如果不是抽象,必須重寫全部抽象函式,sealed終態,不能再被繼承 { public sealed override void setname() { } //sealed函式不能重寫,重寫必須要新增override private T tt; //設定泛型,也可以使用基本原型object public T getT() { return tt; } //設定泛型函式,泛型會自動擦除傳遞過來的物件的類資訊 public void setT(T tt) { tt = default(T); this.tt = tt; } //default獲取預設值,引用為null,值型別為0 } }

Moniter.cs檔案內容如下:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace csharpdemo
{
public class Moniter:Student,Interface2<String>                                 //可以包含多個介面,實現泛型介面
{
    public Moniter():base("monitor"){                                           //派生類構造器,關鍵字base顯示呼叫基類構造器
        Console.WriteLine("派生類無參構造器建立了物件" + name);
    }
    public Moniter(int age){                                                    //派生類單引數構造器
        Console.WriteLine("派生類有參構造器建立了物件"+name);
    }
    static Student mystudent = new Student("moniter",12);                       //靜態物件初始化只在使用時刻在進行,在第一個建立類物件或者第一次訪問靜態資料時才初始化

    //重寫函式的返回型別可以是基類此方法的返回型別的派生型別
    public override string getname()                                            //重寫虛擬函式需要override關鍵字
    {
        Console.WriteLine("派生類獲取名稱" + name);
        //name = base.name + "的派生";
        return name;
    }
    public int getage() { return 11; }                                          //private不能重寫,派生類重名,覆蓋基類私有方法


    new string name = "moniter";                                                //同名變數和靜態變數,不動態繫結到基類引用上,和基類資料儲存在不同的區域,new關鍵字隱藏基類成員
    string task = "幫助老師管理班級";

    public void init1()                                                         //實現介面函式不叫重寫,所以不加override。多介面時應避免介面函式同名
    {
        Console.WriteLine("實現介面1初始化函式,或介面2初始化函式");
    }
    public void init2(String name)                                              //泛型介面
    {
        Console.WriteLine("實現介面2初始化函式");
    }


}
}

Interface1.cs檔案內容如下:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace csharpdemo
{
    public interface Interface1         //interface介面,完全抽象類,介面中不能包含欄位
    {
        void init1();                   //abstract抽象方法,介面自動是public的,介面中,不能有函式定義體,abstract可以不寫
    }
}

Interface2.cs檔案內容如下:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace csharpdemo
{
    //in抗變泛型,不能使用向上轉型來實現泛型方法,介面也支援繼承,介面可以多繼承,extends後可以有多個子介面,介面可以巢狀在類中<A>泛型介面
    interface Interface2<in T>:Interface1
    {
        void init2(T name);             //abstract抽象方法,介面自動是public
        new void init1();               //介面隱藏了基介面的函式
    }
}

Index.cs主程式檔案內容如下:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Threading;

namespace csharpdemo
{
    using System.Text.RegularExpressions;                                               //using為已有型別宣告提供一個新民稱
    using myint = System.IntPtr;
    class index                                                                         //自定義類可以新增static,靜態類不能例項化
    {
        static String stringtemp = "欒鵬除錯";
        static void Main(string[] args)
        {
            var default_age = -2 * -6;                                                  //var型別推斷,區域性變數必須顯示初始化,基本型別也通過物件object兌現,只不過只儲存值,是值型別,一元減號用於轉變資料的符號
            const string default_name = "student";                                      //const常量,編譯時用於計算,不能使用變數對其賦值
            var students=new {name="students",age=12};                                  //匿名型別(在例項化時定義)var型別推斷

            Student.time+=Student.time<<2+0x21^26;                                      //靜態資料,可以直接通過類名訪問,<<位左移動,低位補零,^按位異或,0x表示16進位制數
            Student student1 = new Student();                                           //所有的物件都必須通過new來建立,基本資料型別可以定義建立
            student1.name = student1.getname()+1;                                       //訪問類內資料,字串+過載
            student1.setage(ref default_age);                                           //通過類內函式訪問資料
            Student.Sextype student1_sextype = new Student.Sextype();                   //建立內部類,必須通過外部類變數new構造
            student1_sextype.setsex(Student.allsex.man);                                //呼叫列舉型別
            Student student2 = student1;                                                //僅複製引用,兩個變數名指向同一塊記憶體,可通過實現淺拷貝IShallowCopy和深拷貝IDeepCopy實現全面複製
            if (student1==student2)                                                     //==和!=只是比較物件的引用,不比較物件內容
                if(student1.Equals(student2))                                           //物件的比較使用equals,但是預設的equals還是比較引用,要在自定義類中重寫equals
                    if(default_age is object)                                           //非布林值不能用在邏輯表示式中,is檢測物件是否與型別相容,int資料也是object繼承來的
                        printf("建立了兩個相同的類");

            Random random=new Random();                                                 //隨機數
            int[,] farray = new int[2,3];                                               //鋸齒陣列[2][3],二維陣列[2,3]
            farray[0,0]=random.Next(10,100);                                            //讀取偽隨機序列
            Moniter sub1 = new Moniter();                                               //基類建構函式(繫結後函式),派生類成員,派生類建構函式,介面中的域相當於列舉常量
            sprintf(sub1,null);                                                         //可變引數,null為空引數
            sprintf(sub1);                                                              //傳遞實現介面的類,向上轉化為介面,實現函式回撥
            Student student3 = new Moniter();                                           //基類引用,派生類物件
            student3.getname();                                                         //呼叫引用動態繫結的方法
            ((Moniter)student3).getage();                                               //向下轉型成功
            Interface1 interface1 = new Moniter();                                      //向上轉型,interface1是基類,介面,無所謂,實現介面的類(包含內部類),都可以向上轉化為介面
            interface1.init1();                                                         //呼叫動態繫結的函式

            List<String> allname=new List<String>(){"小明","曉剛","小紅","曉剛","小劉"};
            allname[allname.IndexOf(allname[3])]="小剛";                                  //[]讀取元素,indexof搜尋,沒有返回-1,
            if(!allname.Contains("小王"))                                                 //包含元素
                allname.Add("小王");                                                      //新增元素
            allname.RemoveAt(4);                                                          //刪除下標元素
            allname.Insert(1,"小韓");                                                     //插入元素
            allname.Sort();                                                               //排序

            //link查詢,類似於資料查詢語句,查詢操作本地資料集(資料集類似於二維表)查詢語句就是單個元素的判斷
            var query = from names in allname where names.StartsWith("小") && names.Length==2 orderby names.Length select names;
            foreach(String item in query)                                                  //foreach遍歷時,link語句才執行
                Console.WriteLine(item);

            //list,set,dictionary
            Queue<String> allname0=new Queue<String>();                                     //佇列count元素個數,Enqueue入隊,Dequeue出隊,Peek讀取頭,trimexcess重設容量
            Stack<String> allname1= new Stack<String>();                                    //stack先入後出 堆疊 各種佇列和棧基於linked連結串列實現,count元素個數,push棧頂新增元素,pop棧頂刪除元素,contains是否存在
            LinkedList<String> allname2 = new LinkedList<String>();                         //雙端佇列,佇列,雙向連結串列
            HashSet<String> allname3 = new HashSet<String>();                               //包含不重複元素的無序列表
            SortedSet<String> allname4 = new SortedSet<String>();                           //包含不重複的有序集合
            var allstudent1 = new SortedList<int,string>();                                 //有序列表
            //sorteddictionary有序字典,鍵通過gethashcode對映到索引(陣列),索引關連值。多個鍵可以對映到一個索引,一個索引可以關聯多個值
            Dictionary<int,string> allstudent2=new Dictionary<int,string>();



            try                                                                             //嘗試執行
            {
                StringBuilder sb = new StringBuilder();                                     //stringbuilder包括insert、replace、substring、reverse、append、tostring、delete
                sb.Append(String.Format("這裡%s字串相關操作類","shi"));                   //string.format()   格式化函式,內部建立formatter類設定字串格式
                String outstr = sb.ToString().Replace("shi","是");                          //string是不可變數,取值變化是生成新的類,replace替換,replaceall,replacefirst
                outstr+=outstr.Substring(3)+outstr.Length;                                  //substring取子字串,length字串長度欄位,+過載
                if(outstr.IndexOf("shi")<0)                                                 //indexof查詢子字串的位置,不存在範圍-1,其他字串相關操作較多
                    printf("字串不存在子字串");
                outstr="luanpeng luanpeng";
                outstr = Regex.Split(outstr," ",RegexOptions.IgnoreCase)[0];                //split字串分割,返回陣列,IgnoreCase忽略大小寫
                string patter = "l.an";                                                     //建立正則表示式
                MatchCollection matcher = Regex.Matches(outstr,patter,RegexOptions.IgnoreCase|RegexOptions.ExplicitCapture);   //建立匹配器
                foreach(Match nextmatch in matcher)                                         //依次查詢是否存在匹配
                    printf(nextmatch.Index);                                                //匹配位置

                //int aa=0/0;

            }
            catch (System.Exception ex)                                                     //catch函式在try出錯時呼叫,exception為所有異常的基類,異常可以捕獲派生類異常
            {
                printf("錯誤內容:"+ex.ToString());
                Console.WriteLine(ex.StackTrace);
            }
            finally                                                                         //finally函式總要執行
            {
                printf("finally函式總要執行");
            }

            Student[] all1 = new Student[7];  //
            Student[] all2 = new Student[10];
            all2=(Student[])all1.Clone();                                                   //複製陣列,陣列元素為引用,則輔助陣列的每一個引用項,引用物件資料不復制
            Array.Sort(all2);                                                               //呼叫重寫的排序函式執行陣列排序
            int location = Array.BinarySearch(all2,student1);                               //在陣列中查詢,不存在範圍-1

            president<Student> sub2 = new president<Student>();                             //包含泛型的型別呼叫,也可以不使用泛型建立物件
            sub2.setT(student1);                                                            //將使用型別替換泛型


            //註解
            //資料流
            //序列化
            //Task為後臺執行緒,執行緒池執行緒適合執行短時間程式,均為後臺執行緒,不能設定優先順序
            run();                                                                          //在主執行緒中呼叫run函式
            Parallel.For(2,4,i=>{num=i;run();});                                            //Parallel.For並行for迴圈,沒有順序,引數i從2到4(不包括4),可以設定提前終止條件
            Parallel.ForEach<string>(allname,str=>{stringtemp=str;run();});                 //Parallel.ForEach並行遍歷,沒有順序,可以設定提前終止條件
            Parallel.Invoke(run,run);                                                       //並行執行多個委託
            Task t1 = new Task(run);                                                        //可以建立時向函式傳遞引數,新任務,使用執行緒池中的執行緒
            t1 = new TaskFactory().StartNew(run);                                           //建立任務工廠,並建立啟動新執行緒,使用執行緒池中的執行緒
            t1 = Task.Factory.StartNew(run);                                                //靜態屬性factory建立,使用執行緒池中的執行緒
            t1=Task.Run(()=>{run();});                                                      //lambda表示式為引數重寫task的run函式,使用執行緒池中的執行緒
            //t1.RunSynchronously();                                                        //在當前執行緒(主執行緒),啟動任務
            t1=new Task(run,TaskCreationOptions.LongRunning);                               //新執行緒,不使用執行緒池中的執行緒
            t1.Start();
            t1.Wait();                                                                      //等待執行完成
            //ThreadPool.QueueUserWorkItem(run);                                            //選擇執行緒池中的執行緒執行函式,沒有建立執行緒池會先建立再執行

            //thread預設是前臺執行緒,適合執行長時間函式
            Thread thread =new Thread(run);                                                 //呼叫子執行緒,執行run函式
            thread=new Thread(()=>Console.WriteLine("lambda執行緒函式"));                     //呼叫lambda表示式執行緒函式
            thread.IsBackground=true;                                                       //設定為後臺執行緒
            thread.Priority = ThreadPriority.Highest;                                       //設定執行緒優先順序
            thread.Start();                                                                 //啟動執行緒Start()括號中可以包含一個引數
            thread.Join();                                                                  //等待執行緒結束
            thread.Abort();                                                                 //執行緒中斷,會線上程執行至阻塞時中斷
            new Thread(run).Start();                                                        //新建執行緒執行函式

            //lock(鎖定資源)、Interlocked(提供執行緒安全的遞增遞減交換和讀取值)、Monitor(設定超時,釋放鎖)、waitHandle(等待訊號的出現)
            //mutex(多個程序間同步-通過名稱)、semaphore(訊號量可以由多個執行緒使用)、event(事件通知)
            bool locktaken=false;
            Monitor.TryEnter(stringtemp,500,ref locktaken);
            if (locktaken){
               printf("同步控制塊執行");
                Monitor.Exit(stringtemp);                                                   //釋放鎖
            }

            //在threading、timers、forms、web ui、windows.threading中都有timer,設定重複執行的函式
            //System.Timers.Timer mytime= new System.Timers.Timer(1000);
            //mytime.AutoReset = true;
            //mytime.Elapsed+=run;   //回撥函式引數受到限制的(object sender,system.timers.elapsedeventargs e)
            //mytime.Start();
            //mytime.Stop();

            Showdata datashowfun = new Showdata(printf);                                     //以函式為引數例項化委託,作為回撥函式
            datashowfun = delegate(string str){Console.WriteLine(str);};                     //使用匿名方法實現委託
            datashowfun = str=>{Console.WriteLine(str+stringtemp);};                         //使用lambda表示式實現委託,lambda表示式可以訪問外部變數,這成為閉包。=>左邊列出引數,右邊複製實現函式
            print(datashowfun,"結束");                                                       //委託為引數,呼叫函式

            Console.ReadLine();

        }


        public static void sprintf(Student student, object[] args)                          //基類引數允許傳遞派生類為引數,object[]用於可變引數列表,可以無參呼叫
        {
            student.setname("student");                                                     //呼叫動態繫結的基類函式,修改基類成員
            printf(student.getname());                                                      //呼叫引用動態繫結的派生類重寫的函式
        }
        public static void sprintf(Interface1 interface1)                                   //介面引數允許傳遞介面類為引數,sprintf函式名相同實現過載
        {
            if (interface1 is Moniter)                                                      //is判斷,指向物件的具體判斷,不是引用的判斷
            {
                Student student = interface1 as Student;                                    //先向下轉型為Moniter,在向上轉型為student,as向上轉型,在指定派生類物件的基類引用,可以強制轉化為派生類引用
                printf("介面型別:" + interface1.GetType());                                //獲取引用指向的物件的型別
                student.getname();                                                          //動態呼叫繫結的方法
            }
            interface1.init1();                                                             //介面相當於純抽象類,動態繫結方法
        }

        public static void printf<T>(T str)                                                 //泛型方法,
        {
            Console.WriteLine(str.ToString());  
        }

        public delegate void Showdata(string str);                                          //delegate定義委託,委託名為函式型別名,而不是函式變數名。這是一個輸入為字串,返回為空的函式引用,
        public static void print(Showdata action, string str)
        {
            action(str);
        }

        static int num = 0;
        public static void run()
        {
            num++;                                                                          //自增自減不是執行緒安全的
            Thread.Sleep(1000);                                                             //多執行緒,睡眠,不釋放鎖,自動回覆
            //await Task.Delay(10);                                                         //await一旦完成立即執行,Task.Delay非同步方法,釋放執行緒供其他任務使用,所以此句後面的是新執行緒
            printf(num + stringtemp + DateTime.Now);
        }

    }
}