.NET基礎筆記(C#)


     閑着沒事就把以前學習時的筆記拿出來整理了一下,個人感覺有點用,就想拿出來跟園友共享一下。有些基礎性的內容比如基本概念、語法什么的就不發了。

內容:1、構造方法(函數) 2、繼承   3、訪問修飾符  4、靜態和非靜態  5、隱藏基類方法  6、重寫基類方法  7、抽象方法  8、接口  9、多態和接口  10、值類型與引用類型  11、ref和out  12、類型轉換  13、異常處理  14、string字符串處理  15、string常用方法  16、StringBulider  17、File類讀取文件  18、文本高亮 19、泛型集合List<T>和Dictionary<TKey,TValue>  20、裝箱和拆箱  21、讀寫數據(Ststem.IO)  22、文件流(FileStream)  23、StreamReader和StringWriter  24、File和Directory  25、序列化  26、Directory類的靜態方法  27、正則表達式  28、Regex類  29、字符串提取  30、貪婪模式  31、字符串替換  32、byte數組和字符串的轉換  33、委托  34、多播委托  35、事件  36、委托和事件的區別  37、var類型  38、擴展方法  39、XML

1、構造方法(函數):在對象創建的時候初始化字段

    public 類名([參數])

    {

        //執行內容,如this.name=name;(有參數)

    }

  構造方法沒有返回值,void也不寫

  創建對象時如果沒寫構造方法系統默認有一個無參的構造方法,一旦用戶添加了構造方法,原來默認的無參的構造方法就沒有了

  默認初始值為:int:0;  bool:false;  string:null;   char:‘\0’; 

  構造方法的作用:初始化字段(實例化類的時候傳入初始值)

  調用構造方法:

    1)除了new對象的時候,不能直接使用構造方法名調用構造方法

    2)this調用構造方法(難點)(一個構造方法調用另一個構造方法)

   為了解決代碼的重用才使用this調用構造方法

   當一個類中出現多個構造方法重載的時候,同時構造方法都需要為字段賦初值

   使用this代表當前類的構造方法來使用,根據this后面的參數決定使用哪一個重載

    public 構造方法名():this([參數])

    {

        //代碼

    }

如:  

 public Person(string name, int age, string sex)

        {

            this.name = name;

            this.age = age;

            this.sex = sex;

        }

        public Person(string name)

            : this(name, 0, null)

        {

        }

2、繼承:

  多個類都有共同的字段、屬性或方法時,可以使用繼承

  需要寫一個學生類、一個老師類、一個校長類

  事先寫一個Person類,在寫其他類的時候繼承這個類,Person叫父類,繼承他的叫子類

  特征:子類既有父類的非私有字段、屬性和方法,又有子類獨有的字段、屬性和方法

  一個子類只能有一個父類,一個父類可以有若干個子類

    [訪問修飾符] class 子類名:父類名

子類調用父類構造方法的問題(難點)

  ->構造方法的執行順序:先父類再子類

  ->關於構造方法的重載:如果不聲明調用哪個構造方法默認執行無參的構造方法

  避免錯誤的方法:

->為父類提供無參構造方法

->在子類中指定調用父類有參的構造方法

注意:父類除構造函數(方法)之外的非私有成員都可以被子類所繼承,構造方法不可以被繼承,但可以被調用,調用方法: [訪問修飾符] 構造方法名([參數]):base(父類構造方法的參數)

public Teacher():base("狗蛋”,20,"女")

        {        }    //直接賦值,實例化對象時不需再賦值

 

 public Teacher(string name, int age, string sex)

            : base(name, age, sex)

        {

            this.className = "C#";//老師類獨有的字段

        }   //繼承傳遞參數,實例化對象時需要賦值

  base關鍵字用於顯示聲明要調用父類的哪個構造方法,是調用,不是聲明不是繼承

  注意:為避免繼承父類時因為構造方法出錯,應該為每個聲明的類都手動添加一個無參的構造方法

3、訪問修飾符

  public 最公開的,所有地方都可以訪問

  private 最隱蔽的,只有本類可以訪問

  protected 可以在當前類和子類中被訪問

  internal 只能在本項目中被訪問

  C#中規定類的訪問修飾符只能是public 和internal 

  類中成員的訪問修飾符除以上四種以外還有個(protected internal)即可以在當前類、子類和本項目中被訪問  

4、靜態和非靜態

  靜態使用static標記

靜態成員

  ->如何定義靜態成員

       在成員前加static關鍵字

  ->如何使用靜態成員 

靜態成員不能由實例對象調用,只能用類名調用

使用靜態成員,不需要實例化對象

靜態成員會在整個應用程序退出時才釋放資源,所以這個變量可以在整個程序中共享數據,可用於窗體間傳遞參數

注意:靜態變量過多會占用系統內存,因此聲明靜態變量時要多加考慮

Main方法是靜態的,所以它只能調用靜態的方法或參數,若想調用非靜態方法,必須new一個類的實例,用實例名調用。

靜態類

  1)什么情況下要將一個類標記為靜態類?

      一般情況是,當這個類是一個工具類,里面都是方法,為了讓用戶調用的時候方便,不需要實例化對象,這時可以將該類標記為static類,此時該類中只能包含靜態成員,不能包含實例成員,比如Convert、Console、Read、ReadInt等

  2)什么情況下需要在一個普通類中編寫一個靜態成員,而這個類不能標記為static?

      當這個類需要被實例化的時候,如果這個類中有一個成員是所有對象要共享的數據,這時可以將該類中的這個成員標記為靜態的,但是這個類還是一個非靜態類

  3)靜態類不能被實例化,不能被繼承

  4)由於靜態成員會在整個程序退出時才釋放資源,所以盡量避免寫靜態字段或靜態屬性,最好只寫靜態方法

  5)靜態類中可以有靜態成員和實例成員,因為其不能被實例化,所以靜態類中的實例成員無法被調用,也就沒有任何意義了

  6)靜態類不能被繼承,也不能繼承自其它類,只能繼承自Object類

靜態構造函數

  1)靜態構造方法(或字段)在第一次訪問這個類的時候執行,並且只執行一次

  ->靜態構造方法與靜態類的生命周期(了解)

靜態成員屬於該類的所有對象。實例成員只屬於當前實例

靜態類的生命周期:第一次訪問類的時候創建,程序結束時才釋放

 

5、隱藏基(父)類方法(了解,用的不多)

  當子類和父類有相同名字的方法時,實例化子類調用該方法為子類內的方法,把子類轉換成父類后再調用該方法就是父類內的方法了

  為了代碼規范化,如要有意隱藏父類的方法,要在子類的同名方法前加new關鍵字,用於   提醒這里是要隱藏父類方法

//隱藏基類方法

    class MyBase

    {

        public void Func()

        {Console.WriteLine("我是父類的方法);}

    }

    class MySub : MyBase

    {

        public new void Func() //在方法前用new關鍵字提醒這里是有意隱藏父類方法

        {Console.WriteLine("我是子類的方法);}

    }

    class Program

    {

        static void Main(string[] args)

        {

            MySub ms = new MySub();

            ms.Func();

           // ((MyBase)ms).Func();

            MyBase my = ms;

            my.Func();

            Console.ReadKey();

        }

    }

6、重寫基(父)類方法(多態的體現)

  在父類方法前加virtual(虛方法),表示這個方法可以被重寫

  在子類方法前加override,表示重寫基類方法,子類如果不寫override就是隱藏

 當子類和父類有相同名字的方法時,實例化父類調用的是父類的方法,將子類賦值給父類后,父類調用的就是子類的方法了

  一旦父類的方法在子類中被重寫,除了實例化父類調用以外,子類或者子類的子類調用時都是調用的最新的那個子類重寫方法

  此時base和this就有區別了:

  如果子類和父類中有名字相同的方法,那么base.Func()就代表父類的方法,this.Func()代表當前類的方法

  如果不希望子類再重寫,需要在子類方法前加sealed

//重寫基類方法

    class USB

    {

        public virtual void Usb() //virtual關鍵字表示父類方法可以被重寫′

 

        {Console.WriteLine("我是父類的方法);}

    }

    class Phone:USB

    {

        public override void Usb()//override關鍵字表示這個方法重寫父類的方法

 

        {Console.WriteLine("手機");}

    }

    class Mp3:USB

    {

        public override void Usb()

        {Console.WriteLine("MP3");}

    }

    class Program:USB

    {

        static void Main(string[] args)

        {

            Console.WriteLine("輸入數字");

            USB usb = new USB();

            switch (Console.ReadLine() )

            {

                case "1":

                    usb = new Phone();

                    break;

                case "2":

                    usb = new Mp3();

                    break;

                default:

                    break;

            }

            usb.Usb();

            Console.ReadKey();

        }

}

隱藏看類型,重寫只管新

7、抽象方法

  方法前加abstract,圓括號后加分號

  [public]  abstract  void 方法名(參數);

  抽象方法所在的類也必須是抽象的,不能被實例化,類前加abstract  

  abstract  class  類名

  抽象成員必須出現在抽象類中,但抽象類中可以有抽象成員和實例成員

  抽象類的抽象方法默認可以且必須被重寫,所以需要重寫時不需要再寫virtual,直接在子類方法中寫override關鍵字即可重用

  抽象類的成員:方法、屬性、索引、事件

  注意:抽象類中的所有抽象方法在子類中必須要被重寫,如果子類中不重寫,那這個子類也必須聲明成抽象類,但此時子類也就不能被實例化了

8、接口

  [訪問修飾符] interface 接口名(接口一般以I開頭,I+行為+able)

  {

    //接口成員,一定是抽象成員

  }

  成員的定義:與抽象成員的寫法一樣(沒有關鍵字),沒有執行體(方法體);沒有訪問修符;

  實現:子類“繼承”自接口,接口可以看做是子類的“干爹”,補全抽象的方法

  調用:和類的使用方法一樣,要使用接口中的方法,則將對象賦值給接口變量

  多態:和抽象類的實現一樣,接口的多繼承使得多態的實現變得靈活

  子類繼承父類,子類實現(繼承)接口:class 子類名:父類名,接口名 或class 類名:接口名

  個人理解:接口就是把類中的一種特定的功能性方法封裝成接口(如開車、飛等),聲明類的時候可以繼承這個接口,就擁有了這個接口所特有的功能,就可以在類中實現這個功能,那實現后的這個功能就成為了這個類的一個功能性方法。用接口可以實現多繼承,一個類可以繼承多個接口,也就擁有了多個功能性方法,聲明類的時候可以選擇性的繼承,比如定義老師的時候可以繼承說話、吃飯、教課等接口,定義司機的時候又可以繼承說話、吃飯、開車等接口

//定義一個接口,表示Driving功能

interface IDrivable

    {

        void Driving();

    }

class Teacher:Person,IDrivable//繼承父類和接口

    {

        public Teacher(string name, int age, string sex):base(name,age,sex)

        {//繼承父類的構造方法

        }

        public void Driving()//實現接口的Driving功能

        {

            Console.WriteLine("我會開車");

        }

        public override void ShowMe()//重寫父類方法

        {

            Console.WriteLine("我是老師");

        }

    }

static void Main(string[] args)

        {

            Teacher tea = new Teacher("張三", 18, "男");

            tea.ShowMe();//調用重寫后的方法

            tea.Driving();//調用實現后的接口方法

            Console.ReadKey();

        }

9、多態和接口

  接口是可以多繼承的,多繼承同時會引起方法的重名

  為避免重名,顯示實現接口:

返回值 接口名.方法名(參數)

   {

        //方法體

   }

顯示實現接口的這個方法只能由接口變量進行調用

現階段記住接口使用的語法,然后將接口直接當做抽象類使用(初學階段)

10、值類型和引用類型

  變量可以看做是一個數據

  值類型,是一個存儲數據的容器,這個數據就是這個類型表示的數據

  引用類型,也是一個容器,但是這個容器存儲對象的一個引用(地址),真正的數據在另一塊內存中,就相當於是一個指向數據的快捷方式

  值類型存儲在棧里面,引用類型存儲在棧和堆里面(堆里存儲的是真實數據,棧里面存儲的是真實數據在堆里面的內存地址)

  值類型和引用類型會涉及到傳參和賦值時的不同,要注意區分

 

  委托(delegate)也是引用類型

  值類型賦值賦的是真實的值,引用類型賦值賦的是地址

  引用類型是一個變量,兩個快捷方式,修改一個快捷方式會影響另一個快捷方式;值類型是一個變量和一個復制后的變量,修改一個變量不會影響另一個變量

  所有的值類型都繼承自System.ValueType類

11、引用傳遞:ref和out

  使用ref或out就可以實現將引用傳遞過來

  定義方法時,在參數類型前加ref或out

  調用方法時,在參數前加ref或out

  注:定義變量時不需要加ref或out

  當一個變量傳遞給一個方法時,總是復制一份自己的數據,賦值給方法,那么方法中執行的變量就與方法外的那么變量沒有關系了,方法內修改變量值,也不會影響方法外的那個變量。有時會要求多個返回操作(方法中的變量有多個在方法外需要使用),此時可以使用ref標記參數,此時在方法中使用的這個變量與方法外的變量就是同一個變量了,相當於可以使用參數實現返回值

    out與ref的作用與使用方法相同

  out 必須在方法中賦值

  ref必須在方法外賦值

12、類型轉換

  隱式類型轉換:兼容類型,小轉大

  顯式類型轉換:即強制類型轉換  (轉換后的類型)要轉換的變量

  Convert類型轉換:系統封裝的方法,Convert.ToInt32()、Convert.ToDouble()等

  其他轉換方法:int.Parse()、int.TryParse()(第一個參數表示待轉換的字符串,第二個out(result)參數表示數字轉換成功后的變量,如果轉換失敗,返回false,為out result賦值為0)

  用int.TryParse()代替try-catch,釋放內存,提高性能

  不止int類型有TryParse,所有基本類型都有TryParse,用法都一樣

13、異常處理(try-catch、try-catch-finally、try-finally)

  Exception是一個專門用來封裝異常的一個類型

  兩個屬性:message(異常說明文本)和stackTrace(異常拋出的順序)

  拋出異常:throw Exception的一個對象(new一個對象)

  從出現異常的try向上依次拋出(方法之間依次調用),直至處理,找到最近的catch捕獲異常(用於try-finally語句,catch塊在方法以外,執行順序是try-finally再向上尋找catch執行異常捕獲)

Finally用於釋放資源,finally{},程序執行完try-catch后會再執行finally語句塊

Finally總會執行,即使try-catch中有return

           try

            {  }

            catch (Exception ex)

            { throw; }

            finally

            {  }

Try-finally用處不多,用於釋放資源

使用異常會降低系統性能,盡量少用

14、string字符串處理

構造函數:string(char[] chs)、string(char ch,int count)

  string str = new string(’a‘,’b’,’c’);//abc

  string str = new string(‘a’,3);//aaa

  3.144.ToString(“0.0”);用於控制格式,會四舍五入

字符串可以當做數組進行處理(使用下標讀取,擁有數組的各種屬性)

  string str = “不可見的你”;  此時str[1]就是“可”了

  通過索引得到的數據是char類型,字符串不可改變,使用索引無法修改字符串的數據

  要想修改可將字符串變成字符型數組,str.ToCharArray()

string是引用類型

string str = string.Empty;聲明一個空字符串

  判斷字符串是否為空:

str.Length == 0(推薦)

str ==“”

str == string.Empty

String.IsNullOrEmpty(要判斷的字符串)(推薦)

15、string常用方法

  1)字符串比較:bool isTrue = string.Equals(string a,string b)

  String.Equals(str1,str2);

  Str1.Equals(str2,StringComparison.OrdinalIgnoreCase); //第二個參數意思是不區分大小寫

  string.Compare(str1,str2);

  Equals方法:

String重載的方法判斷兩個,一個是==,一個是EqualsHelper

==判斷兩字符串是否相同

EqualsHelper判斷兩個字符串中每一個字符是否相同

  Object的重載是來自於object類,是繼承下來的

在object中使用的是==和Equals方法

Equals方法是一個虛方法,由string重寫了,調用的是object.ReferenceEquals方法和EqualsHelper方法

注意:==默認表示判斷兩個對象的地址是否相同,與object.ReferenceEquals方法一樣

String提供的str1.Equals(str2)判斷地址是否相同,字符串是否object提供的virtual Eaulse(object)

Equals和==的區別:

  Equals會判斷兩個值的內存地址;==只判斷值是否相等。

Compare方法:

  int result = String.Compare(str1,str2);

  str1>str2 -> 1    str1 == str2 -> 0   str1<str2 -> -1

  string.Compare方法比較兩個字符串,這兩個字符串字母順序表示大小,按照字典排序規則進行比較(對於char類型:A>a,B>a,b>A同一個字母,大寫>小寫,不同字母按照字母順序后面的大於前面的;對於string類型不是按照埃克森碼比較,A>a,b>A,B>a)

  2)大小寫轉換:ToLower()和ToUpper()

  3)str1 = str1.Trim([params char[] chs]);去除字符串兩邊的空格,或chs中出現的字符(重載)

     str1 = str1.TrimEnd(params char[] chs);去除字符串的末尾chs中出現的字符

     str1 = str1.TrimStart(params char[] chs);去除字符串的開頭chs中出現的字符

  4)合並與分割

合並字符串:string s = string.Join(str1,str2,str3,...)

分割字符串:string[] strArray = str1.Split(‘a’);

                string[] strArray= str1.Split(new char[]{‘a’,’b’},StringSplitOptions.RemoveEmptyEntries);去掉a、b和所有空格

  5)字符串查找

Contain包含,返回bool類型的值,str1.Contain(“愛”);

IndexOf檢索位置,返回字符串中某個字符的位置(int)找不到則返回-1

str.IndexOf(要找的字符或字符串)

str.IndexOf(要找的字符或字符串,開始尋找的位置)

str.LastIndexOf()是從后往前尋找,用法同str.IndexOf() 

注意:IndexOf和LastIndexOf中第二個參數(開始尋找的位置)只是為了說明要查找的是字符串中的哪一個字符(如果字符有重復),即按查找順序在開始位置后的第一個字符,返回的索引依然是該字符在整個字符串中的索引,而不是從查找位置開始的索引。

  6)截取子字符串

string s =str1.Substring(開始的位置,子字符串的長度)

String s = str1.Substring(開始的位置)

  7)判斷字符串的開頭和結尾

bool a = str1.StratWith(字符串);

bool a = str1.EndWith(字符串);

  8)字符串的插入、移除和替換

插入:string str2 = str1.Insert(位置(int),要插入的人字符串(string));

移除:string str2 = str1.Remove(位置(int),長度(int));

      string str2 = str1.Remove(位置(int));移除該位置后的所有字符

替換:string str2 = str1.Replace(舊字符串,新字符串);

  9)格式化字符串

String.Format(格式化的字符串,填坑的參數)

string str1 = String.Format(“{0},{1}”,str2,str3);

  10)判斷字符串是否為空

    String.IsNullOrEmpty(str);

  10)字符串的方法(總結)

增:添加(+=)、插入(Insert)

刪:Remove

改:Replace、 ToUpper、ToLower、Trim、TrimStart、TrimEnd、Split、Join、new String、SubString、Format

查:Contains、IndexOf、LastIndexOf、StartsWith、EndsWith、ToCharArray、Length、Empty

比:Equals、Compare

16、StringBuilder

大量字符串拼接的時候性能非常差,很難完成大型數據的拼接

(Stopwatch對象可以記錄程序運行的時間,Start開始計時,Stop結束)

使用StringBuilder:StringBuilder sb = new StringBuilder();

  sb.Append(要添加的字符串);//向sb中添加數據

  sb.AppendLine(要添加的字符串);//向sb中添加數據后換行,等價於sb.Append(要添加的字符串+”\r\n”);

  sb.AppendFormat(要添加的字符串);格式化處理,等價於 sb.Append(string.Format(要添加的字符串));

  string str = sb.ToString;輸出或賦值時要轉換成string

在處理大型數據的時候,StringBuilder要比普通的string處理快很多,因為處理大型數據要用StringBuilder

17、讀取文件

  string[] lines = File.ReadAllLines(@"H:\傳智播客實訓資料代碼\第9天\a.csv", Encoding.Default);//按行讀取

  string[] lines = File.ReadAllText(@"H:\傳智播客實訓資料代碼\第9天\a.csv", Encoding.Default);//讀取所有文本

  string[] lines = File.ReadLines(@"H:\傳智播客實訓資料代碼\第9天\a.csv", Encoding.Default);//讀取一行文本

  string[] lines = File.ReadAllBytes(@"H:\傳智播客實訓資料代碼\第9天\a.csv", Encoding.Default);//讀取字節

18、文本高亮

->讓文本框獲得焦點--txtContent.Focus();

->找到要高亮的位置--pos

->選中(高亮)的字符串長度--length

->調用TextBox的選中方法txtContent.Select(pos,length)

19、泛型集合   List<T>和Dictionary<TKey,TValue>

List集合:動態的自定義數組

  List<類型> 集合名 = new List<類型>();

List用法與ArrayList一樣,不同點在於定義時和使用時的類型固定,因此可以完全替代ArrayList

  類型[] = list.ToArray()//將List轉換成該類型的數組

Dictionary集合:動態的自定義鍵值對

  Dictionary<類型,類型> 集合名 = new Dictionary<類型,類型>();

Dictionary用法與Hashtable一樣,不同點在於定義時和使用時的類型固定,因此可以完全替代Hashtable

20、裝箱與拆箱

  直接將值類型賦值給引用類型就是裝箱

  將存儲值類型的引用類型強制轉化為對應的值類型就稱為拆箱

Object o = 1;//裝箱      int n = (int)o;//拆箱

  裝箱對值類型保持無關性,裝箱對引用類型保持相關性

  裝箱和拆箱會對性能有一定的影響

21、讀寫數據(I/O操作、System.IO類)

  System.IO.Path類,專門處理字符串路徑,是一個靜態類

    string path = @“D:\window\system\file.txt”; 

    獲取文件名:string fileName = Path.GetFileName(path);

    獲取后綴名:string fileName = Path.GetExtension(path);

    修改后綴名:path = Path.ChangeExtension(待修改的路徑,“mp3”);

    獲取文件夾名:string fileName = Path.GetDirectoryName(path);

    合並路徑:path= Path.Combine(路徑1,路徑2,路徑3...);

    臨時文件夾:path = Path.GetTempPath();

  絕對路徑:從盤符開始的最精確的路徑

  相對路徑:相對於當前文件同一個目錄作為參照的路徑

  相對路徑和絕對路徑:區分就看有沒有根目錄盤符的標記

22、文件流(FileStream)

  1)引入命名空間

  2)創建FileStream對象FIleStream fs = new FileStream(文件名,FileModel,FileAccess)

FileStream fs = new FileStream(@"D:\a.txt", FileMode.Create, FileAccess.Write);

FileModel:對文件的處理方式(打開、創建、追加)

FileAccess:對文件的操作:讀、寫

  3)使用方法操作

寫一個字節:fs.WriteByte()

寫一個字節片段(將字節數組中的數據寫入到fs指定的文件):

  fs.Write(存放字節的數組,開始寫字節的數組下標,要寫的字節數)

讀一個字節:fs.ReadByte()

讀一個字節片段(將fs指定的文件中的數據讀取到字節數組):

  fs.Read(存放字節的數組,開始存放字節的數組下標,要讀的字節數)

  4)釋放資源

fs.Close()和fs.Dispose()方法(兩個都要調)

23、StreamReader和StreamWriter

  StreamReader:專門用來讀取文本文件的流

1)引入命名空間:IO

2)new一個FileStream指向文件

3)new一個StreamReader,構造函數參數是FileStream的對象

4)調用方法

    StreamReader有一個屬性EndOfStream:判斷當前的流位置是否在文件流的末端,一般用來判斷文件是否讀完

  StreamWriter:專門用來寫入文本文件的流

1)引入命名空間:IO

2)new一個FileStream指向文件

3)new一個StreamWriter,構造函數參數是FileStream的對象

4)調用方法

24、File和Directory對文件和目錄操作做了一個封裝

增(Create):創建文件或文件夾  

刪(Delete):刪除文件或文件夾  

改:改名字 File.Move(“1.txt”,“2.txt”)

查:...

判斷是否存在(Exists)

移動文件:File.Move(“1.txt”,“2\1.txt”)

復制文件:Copy

  Directory用於處理文件夾(目錄)

刪除目錄的時候如果目錄不是空的則會報錯,此時需要在Delete內添加一個true

Directory.Delete(“1”,true);

25、序列化:

  序列化:把一個對象的內容存儲到磁盤上(文件流)、網絡上(網絡流)、內存里(內存流),下次需要用到對象數據的時候可以直接拿來用

  反序列化:把已經序列化存儲到磁盤、網絡、內存里的對象數據,提取到項目中的對象中

序列化步驟:

1)創建一個文件流

2)為需要序列化的對象添加標記([Serializable]表示此對象可以被序列化)

3)創建BinaryFormatter(導入命名空間)

4)調用Seralize方法(bf.Seralize(文件流對象,需要被序列化的對象))

反序列化步驟:

1)創建一個文件流

2)為需要序列化的對象添加標記([Serializable]表示此對象可以被序列化)

3)創建BinaryFormatter(導入命名空間)

4)調用DeSeralize方法(object ob = bf.DeSeralize(文件流對象))

反序列化定義接收類型的時候必須根據原序列化的程序集確定類型

  建議:在使用序列化的時候盡量避免使用自動屬性,因為自動屬性在每次編譯的時候自動生成的字段名可能不一樣,所以在反序列化的時候可能會造成問題

  注意:如果序列化和反序列化不在同一項目下,那反序列化的時候需要引用原序列化的程序集

26、關於文件夾下的文件與子文件夾

  Directory類的靜態方法

獲取子文件名:string[] s = Directory.GetFiles(@“D:\dir“);

獲取特定后綴名的子文件名:string[] s = Directory.GetFiles(@“D:\dir“,”*.txt“);

獲取所有文件夾名:string[] s = Directory.GetDirectories(@“D:\dir“);

27、正則表達式

  元字符:

1).(點)表示除\n以外任意的單個字符

2)[ ]表示括號內的任意一個字符(如a[xyz]b表示axb或ayb或azb)

3)^在[ ]括號內表示取反(如^[a-z]表示除小寫字母以外的所有字符)

4)^匹配一串字符的開始(^abc表示以abc為開頭的任意字符串)

5)$匹配一串字符的結尾(abc$表示以abc為結尾的任意字符串)

5)|表示“或”,優先級最低(如a|bc表示a或bc,(a|b)c表示ac或bc)

6)()可以改變優先級、提取組

7)*表示限定前面的字符出現任意次數(abc*表示ab、abc、abcccc......(abc)*表示abc、abcabc)

8)+ 至少出現一次,也可出現多次(xa+y表示xay、xaay...)

9)?表示出現0次或1次

10){n}限定前面的表達式出現n次

11){n,m}至少出現n次,最多出現m次

12){n,}至少出現n次

13)\d表示0-9,\D表示\d的反面

14)\s表示空白符,\S表示\s的反面

15)\w表示數字、字母、下划線、漢字,\W表示\w的反面

注:正則表達式的轉義符也是\,如果要表示*(星),可以寫成\*,要表示一個\,可以寫成\\

28、Regex類

  Regex.IsMatch(待判斷的字符串,正則表達式)判斷一個字符串是否匹配某個正則表達式

  !如果正則表達式沒有^和$,那默認不設定開頭和結束,此時只要待判斷的字符串中含有該正則表達式就返回true

  ^z|food$:表示以z開頭的任意字符串或者以food結尾的任意字符串,都返回true

             因為|的優先級最低,所以上邊的表達式其實是(^z)|(food$)

  Regex.Match()從某個字符串中提取匹配某個正則表達式的某個子字符串,但只能提取一個

  Regex.Matches()同上,可以提取所有的匹配字符串

  Regex.Replace()字符串替換,把所有匹配正則表達式的字符串替換為對應的字符

29、字符串提取

  字符串提取的時候一般不加^和$  

  Match m = Regex.Match(原字符串,要提取的正則表達式)

  m.Value屬性表示提取到的字符串

  m.Group[n]:提取組,按正則表達式中()括號對的個數,m.Group[0]表示整個字符串,m.Group[1]表示第一個括號內的內容,所以提取組的時候要從下標1的地方開始

  MatchCollection mc = Regex.Matches(原字符串,要提取的正則表達式)

  MatchCollection是一個集合,需要foreach遍歷輸出(遍歷時的類型是Match)

30、貪婪模式

  定義:當正則表達式提取的時候,如果一個字符或多個字符都能匹配,這時會按照使用最多字符的方式來匹配。

  正則表達式默認采用貪婪模式,盡多的匹配

  在限定符后面使用問號用來終止貪婪模式,即只會提取匹配的第一個

  string s = “aaaa bbbbbbbb”;string s1 = “[a-zA-Z]+”;  匹配結果:aaaa

  string s = “aaaa bbbbbbbb”;string s1 = “[a-zA-Z]+?”;  匹配結果:a

31、字符串替換

  String s =Regex.Replace(原字符串,待替換的正則表達式,替換后的字符串);

  如:string s = Regex.Replace(s, "-+", "-");//把字符串s中的所有-替換成一個-

  提取組替換:

            string s = "aaa13812345678bbb";

            s = Regex.Replace(s, @"(\d{3})(\d{4})(\d{4})", "$1****$3");//把手機號中間4位替換成4個*

32、byte數組和字符串的轉換

  byte[] bt= System.Text.Encoding.UTF8.GetBytes(str);

  string str = System.Text.Encoding.UTF8.GetString(bt);

33、委托(delegate)

  委托是一種數據類型(和類一樣),可以將方法賦值給委托對象,可以理解為方法類型

  定義(在命名空間下,或添加一個cs文件,和類的定義一樣):

1)使用delegate關鍵字

2)這個委托將來要存儲的方法如果沒有返回值,那么委托也要定義成void,參數也要與方法保持一致

3)委托是一個數據類型,用的時候需要傳遞一個變量

4)創建委托對象的時候可以不用new,系統編譯時會自動給我們new

定義委托類型:public delegate void ChangeTxtDelegate(string str);

創建委托對象:public ChangeTxtDelegate changeTxt;  //Form1中

    給委托賦值:f1.changeTxt = ChangeText;  //Form2中

調用委托:changeTxt(txt);  //Form1中,此種調用方法為簡寫,實際上是changeTxt.invoke(txt);

創建委托對象時也可直接對其賦值:ChangeTxtDelegate changeTxt = new ChangeTxtDelegate(ChangeText) ;

  用法(窗口間傳值):委托要聲明在需要被傳值的對象內,比如Form1要提取Form2中的數據(即Form2往Form1傳值),就應該把委托聲明在Form1中,在Form2中寫一個方法獲取要傳的數據,並且賦值給Form1的委托,最后在Form1中調用委托就ok了。(委托聲明位置不絕對,還需要考慮當前活動窗口的問題,要聲明再活動窗口中,有時也可聲明在被提取值的窗口內)

  作用:可以在某個代碼內部,嵌入一段外部代碼(外部寫一個方法賦值給委托或在定義方法時把委托類型作為參數,調用時把方法名作為參數傳遞給委托對象,那么委托就執行該方法,不同的外部項目可以寫不同的方法賦值給委托,可以實現一個委托選擇性執行多種方法的靈活性),相當於是注入

  什么情況下使用委托?

    當一個類型中需要嵌入一段代碼,但是這段代碼具有不確定性,是根據使用這個類型的用戶來確定代碼的,這時就可以在該類型中使用一個委托,保證在某種情況下會調用該委托,用戶將對應的方法傳遞給該委托,就會調用這個方法

  可以把靜態方法或者私有方法賦值給委托了變量,賦值后只要能使用到該委托變量的地方就能使用該方法,打破了訪問修飾符的限制

  一般在調用委托前或者觸發事件前,都要判斷委托變量或事件是否為null,如果為null則不調用

34、多播委托

  MyDelegate md = new MyDelegate(M1);  md+=M2;(增加某個方法)md-=M4;(去掉某個方法)

  使用委托時,如果不是+=而是直接用=賦值,則會將前面增加的所有方法都覆蓋掉

  多播委托可以存儲多個方法,委托中方法調用的順序與增加方法時的順序是一致的,但是,不要依賴於這個順序(微軟沒有承諾這樣的順序,萬一以后改了就GG了)

  多播委托中,如果要是有返回值,只會得到最后一個方法返回的結果。可以通過調用GetInvocationList()方法返回當前委托中的所有方法,返回值類型時一個Delegate數組(委托數組),再用foreach遍歷調用所有方法

  所有定義的委托都繼承自抽象類MulticastDelegate,而MulticastDelegate又繼承自Delegate抽象類

  多播委托內部是將綁定在當前委托對象上的每個方法,都轉換成一個委托對象,並且存儲在了一個叫_invocationList的object數組中。當調用委托的時候,其實就是循環遍歷_invocationList數組,並且調用其中的每個委托

  多播委托中,如果其中的某個方法執行時發生了異常,則后面的方法不再執行。

  多播委托中只能存儲同一類型的委托,即返回值、參數都相同

35、事件

  事件是在特定條件下執行的動作,這個動作是由用戶確定的。如Button的Click事件,其動作是由程序員寫的,因此可以用委托來實現這個功能,寫不同的方法賦值給委托變量。

  但用委托模擬方法有兩個缺點:

  1)定義的委托可以在類外部的任何地方被觸發,即非特定條件下也可以調用。因為委托變量是public修飾,改為private就不能在外部賦值了。

  2)由於委托可以用=(等號)賦值,所以就有可能把前面已經注冊的事件處理程序都覆蓋掉。

  而用事件就可以解決以上問題:

  1)用事件必須先定義一個委托,否則無法使用事件

  2)實例化委托變量的時候,在委托類型名前面、訪問修飾付的后面加event關鍵字,就定義了一個事件

  3)使用方法與委托一樣,只是避免了以上兩個問題

  4)由於事件只能有+=或-=賦值,所以就避免了用=(等號)賦值時覆蓋前面事件處理程序的問題

  5)由於事件不能在定義事件的類以外被觸發,所以也就避免了冒充事件觸發的問題。

36、委托和事件的區別(面試常考)

  委托和事件沒有可比性,委托是數據類型,事件是委托類型的變量

  委托可以用+=、-=、=賦值,可以在類的外部被調用

  事件只能用+=、-=賦值,不能在類的外部被調用

  事件的內部是用委托實現的

  事件的作用和委托變量(不是委托,是委托變量)一樣,只是在功能上受到一定的限制

37、var類型

  var只能用作局部變量,可以賦任何類型的值。

  var a = 1;和int a = 1;兩者完全一樣

  var不能作為類的成員的類型,不能用作參數,不能用作返回值,只能用作局部變量

38、擴展方法(不修改微軟系統方法源代碼,實現系統方法的增加)

  1)添加一個靜態類

  2)在靜態類中增加一個靜態方法,方法參數是:(this+要擴展的類名+變量名,該方法的參數)

  如要在string類中添加一個驗證是否是Email格式的擴展方法:

        public static bool IsEmail(this string str)

        {

            return Regex.IsMatch(str, @"^\w+@\w+\.\w+$");

        }

            string a = "1321321@qq.com";

            Console.WriteLine(a.IsEmail());

  擴展方法只是看起來像類中的方法,其實不是,所以在擴展方法中也訪問不到類中原來的私有成員

  因為會擾亂系統方法,所以不建議使用,盡量不用

39、XML

  XML是用一種格式化的方式來存儲數據,可以用記事本打開

  1)XML有且只有一個根元素

  2)有開始標簽就必須得有結束標簽,且區分大小寫

  3)元素的屬性值要用引號

  讀取XML文件,通過XDocument(需要添加命名空間)

  讀取整個XML文件: XDocument xd = XDocument.Load(XML文件路徑)

  循環遍歷每個節點:

1)獲取根節點  XElement xeRoot = xd.Root;(xeRoot.ToString()表示XML文檔的內容)

2)遞歸遍歷XML中的每個節點

  遍歷xeRoot下面的所有子節點:

     public static void GetEle(XElement xe)

            {

                foreach (XElement ele in xe.Elements())

                {

                    Console.WriteLine(ele.Name);

                    GetEle(ele);

                }

            }

           GetEle(xeRoot);

例:讀取XML數據

<CFX>

  <MSG>

     <交易碼val="1000" />

     <流水號val="100000000000000001" />

     <金額val="1234567890.12" />

     <付款機構val="1234" />

     <付款單位賬號val="12345678901234567890" />

     <收款機構val="1234" />

     <收款單位賬號val="12345678901234567890" />

  </MSG>

  <MSG>

     <交易碼val="1000" />

     <流水號val="100000000000000002" />

     <金額val="1234567890.12" />

     <付款機構val="1234" />

     <付款單位賬號val="12345678901234567890" />

     <收款機構val="1234" />

     <收款單位賬號val="12345678901234567890" />

  </MSG>

</CFX>

    VS中讀取XML的數據:

            XDocument xd = XDocument.Load("ytbank.xml");  //加載XML文件

            XElement xeRoot = xd.Root;  //獲取根節點

            foreach (XElement item in xeRoot.Elements())  //遍歷根節點,獲取第一級子節點(MSG)

                {

                  foreach (XElement itema in item.Elements())  //遍歷第一級子節點,獲取第二級子節點

                    {

                    Console.WriteLine("{0}:{1}", item.Element(itema.Name).Name, item.Element(itema.Name).Attribute("val").Value);  //獲取節點名和屬性值

                    }

                Console.WriteLine("==================================");

              }

XML寫入:

            XDocument xdoc = new XDocument();  //創建一個XML對象

            XElement xeleRoot = new XElement("Websites");  //創建一個根節點

            xdoc.Add(xeleRoot);  //將根節點添加到XML文件中

            xeleRoot.SetElementValue("baidu", "http://www.baidu.com");  //添加一個節點以及內容       

            XElement xeleGoogle = new XElement("website");  //創建一個節點

            xeleGoogle.SetAttributeValue("url", "http://www.google.com");  //添加屬性和屬性值

            xeleGoogle.SetElementValue("name", "谷歌"); //為節點添加子節點

            xeleGoogle.SetElementValue("age", "14");

            xeleGoogle.SetElementValue("boss", "謝蓋爾");

            xeleRoot.Add(xeleGoogle); //將節點添加進根節點

            xdoc.Save("website.xml");  //保存一個XML文檔路徑

 

 

           

 

 


免責聲明!

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



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