複習、
一、引用類型與值類型
--》文件的複製與快捷方式的複製
二、垃圾回收程序員
三、靜態與非靜態
--》如何定義靜態成員與靜態類
--》如何調用靜態成員算法
四、異常數組
-》託管與非託管
-》.net frameworl
主要分爲三個東西:CLR、CTS、類庫
-》由CLR管理的代碼就是託管的,不然就是費託管的(如File.Create)
->異常是一個類,須要拋出一個異常就要new
-》thorw關鍵字,拋出
2、經常使用類庫--String
大寫的String與小寫的string有什麼不一樣?
-》能夠說兩個都同樣
-》String是一個類
-》構造方法 new string(char [] shs)
2)兩個經常使用的屬性(Length/Empty(常量))
-》length 這一點與數組的用法相似
-》str[0]這個中括號就不叫下標,叫索引
經常使用的方法(索引的使用、ToCharArrray)
不可變性
既然是不可變的,那麼多個字符串,結果相同的時候,就沒有必要每次生成一個對象(節省資源)
3)字符串拘留池(暫存池)
因爲有字符串拘留池的存在,若是代碼中有大量的字符串的值相同,那麼他們都指向同一個對象,
整個代碼中只建立一個對象。
字符串的內部實現與C語言的字符串的實現同樣,能夠參考 IL Assembly這本書ide
4)字符串的處理經常使用的
-》比較
1)Equals方法
-》靜態的Equals方法
-》非靜態的(string的/object的)
Equels方法法有三個重載,StringComparison是個枚舉 OrdinalIgnoreCase表示不區分大小寫比較。
// Equals方法
// -> 靜態的比較方法(靜態方法由類名點出來的)
工具
string str1="abcd"; string str2="ABCD"; if (string.Equals(str1, str2, StringComparison.OrdinalIgnoreCase)) { Console.WriteLine("相等"); } else { Console.WriteLine("不等"); } // -> 非靜態(string的,object的)(實例方法是有對象點出來的) if (str1.Equals(str2, StringComparison.OrdinalIgnoreCase)) { Console.WriteLine("相等"); } else { Console.WriteLine("不等"); }
string.Compare方法是靜態方法,比較兩個字符串大小,比較的的是沒一位字符的unicode碼,
比較規則:分別從兩個字符串的第一位兩兩相比,若是第一位相等就再比較第二位,知道比出大的爲止。
注意:如「22」和「123」相比,此時比較第一個‘2’比‘1’大,那麼就後面的不會再比較了,此時「22」比「123」大
學習
string str1="12"; string str2="23"; if (string.Compare(str1, str2) > 0) { Console.WriteLine("大於"); } else { Console.WriteLine("小於"); }
-》修整
Trim()方法,修整字符傳收尾的空格,,並將新的字符串返回
Trim(praram char [] chs),去除字符數組中出現的字符
TrimEnd() 去掉右邊的
TrimStart() 去掉左邊的
-》檢索
增長:
移除
查找
contains()
indexof()
lastindexof()ui
-》分割與合併this
-》格式化
3、StringBuilder
->Appand() 追加
-》AppandLine 追加換行 至關於 Appand(「123\n」)
->AppandFramart 格式化
StringBuilder輸出的時候記得要ToString()一下
spa
1)string.format 格式化字符串(就是挖坑填坑)
能夠參考console.writeline(「{0}{1}」,str1,str2);不一樣的是conbsole.writeline()是輸出,Format是把它做爲一個字符串返回。
-》@符號的兩個好處:1)能夠取消轉義
2)寫字符串的時候能夠換行
2、集合
爲何要有集合?
數組不是動態的,他的長度動態的變更,爲了擬補這些就有了集合
能夠認爲,集合就是一個動態的數組,而且提供了一些處理的方法.net
1)增、
ArrayList裏面能夠存聽任何類型的數據,裏面存放的數據類型是object的 (arraylist要引入命名空間 shift+alt+F10)
arrayList.Add(要添加的數據); (這是個實例方法)
arrayList.AddRange(數組); 這裏要注意Add方法也能夠放一個數組進去,可是不一樣的是Add方法是把整個數組當成一個集合的元素存到集合裏去,
而AddRange方法是把數組的每一個元素排列放到集合裏去。
2)刪、
Remove() 把指定的元素刪除,若是集合裏沒有這個元素就會忽略掉,不會報異常
RemoveAt() 把集合裏指定下標的元素刪除,若是這個下標超出集合的長度就會報異常
3)改、
和數組同樣經過下標改。直接賦值
4)查
contains(要查找的元素)
若是集合裏有這個元素會返回一個true,不然返回false
5)插入
arrayList.Insert(要插入位置的索引,要插入的數據);
arraylist最大缺點就是Arrayliat是object類型,處理數據須要考慮類型兼容
須要把集合裏的數據拿出來的時候須要強制轉換,因爲是object類型存什麼類型的數據均可以,當集合裏存的數據多的時候
咱們強制轉換就會就會比較麻煩,爲了解決這個問題,List<>泛型集合就出現了。
2)Hashtable<鍵,值>
-》Hashtable的出現就是爲了讓咱們便於查找集合裏的數據的,
-》hashtable裏面存的是一個 鍵 和 值。他們都是object類型的,能夠存聽任何類型的。
-》hashtable的鍵就至關於一個標記,要查找的時候能夠經過 hashtable.Contains(要查找的鍵);方法就能夠快速的找到這個鍵對應着的值(它是經過一個哈希散列算法來實現的)
I、增
hashtable.Add(鍵,值); //hashtable只有一個增長的方法,裏面能夠聽任何類型的數據。
II、刪
Remove(鍵);
-》咱們知道ArrayList是經過下標來刪除的,那麼 咱們的hashtable也是相同的原理,hashtable的鍵就至關於arraylist的下標,
若是把鍵改爲0、一、二、三、四、5........那麼就至關於一個ArrayList,那麼能夠獲得結論,hashtable[鍵] 經過中括號 鍵來刪除。
3、泛型集合
List<T> 這個尖括號裏寫什麼類型這個集合就存什麼類型的數據
-》list就至關於一個規定好存放類型的ArrayList,
->當咱們規定好類型後就能夠解決類型兼容的問題了,從幾何裏取數據時就方便多了。
List的增、刪、改、查方法跟ArrayList同樣。
Dictionary<鍵,值>
->Dictionary對應的就是hashtable,咱們能夠規定好鍵和值的類型,使用起來更加的方便
-》遍歷的三種方法
foreach (string item in dic.Keys) //經過鍵來遍歷 { Console.WriteLine(item); Console.WriteLine(dic[item]); } foreach (Person item in dic.Values) //經過值來遍歷 { Console.WriteLine(item); } foreach (KeyValuePair<string,Person> item in dic) //咱們有時候遍歷的時候要同時用到集合的鍵和值,就能夠經過這個方法 { //KeyValuePair也是一個集合 Console.WriteLine(item.Key + " "+item.Value); }
遍歷集合用foreach, ArrayList和hashtable使用要引入命名空間,而List和Dictionary不用,能夠看出微軟提倡咱們用 List和Dictionary
2、foreach (能夠遍歷任何實現了IEnumerble接口的對象)
foreach(臨時數據類型 臨時變量 in 要遍歷的集合)
{
//將臨時變量做爲遍歷的數據使用
}
要知道臨時數據類型是什麼類型的能夠先寫個var 而後在下面設個斷點,再把光標放到var上去,就能夠獲得當前遍歷的集合是什麼類型了
儘可能不要用var
4、裝箱與拆箱
值類型轉換爲引用類型就是裝箱
應用類型轉換爲值類型就是拆箱
對值類型裝箱保持不變性,對引用類型不保持保持相關性()
Dotnet學習_遞歸篇
3、遞歸
遞歸就是調用本身
--》怎麼調用?(遞推關係)
--》何時跳出
等差數列
2 4 6 8 10 ...
求第n項
2n
Func(n) = Func(n-1) + 2
Func(n) = (Func(n-1-1)+2)+2
。。。
Func(n) = (Func(1)。。。)。。。+2
寫遞歸
--》首先要找到遞推關係
--》臨界條件
小練習_神探福爾摩斯小說
private void Form1_Load(object sender, EventArgs e) { //先添加一個根節點 TreeNode tn = tvwDir.Nodes.Add("神探福爾摩斯-柯南.道爾"); //得到文件的路徑 string path= Path.GetFullPath ("txt"); RecAdd(tn, path); } private void RecAdd(TreeNode tn, string path) { //得到這個路徑下的全部子目錄 string [] dirs = Directory.GetDirectories(path); //得到這個路徑下的全部子文件 string[] files = Directory.GetFiles(path); //循環把全部的子目錄添加到父節點下 foreach (string item in dirs) { //從絕對路徑裏提取文件名 string file= Path.GetFileNameWithoutExtension(item); TreeNode tn1= tn.Nodes.Add(file);//目錄名添加到父節點下 //遞歸調用,由於不知道子目錄下還有多少個子目錄,因此遞歸調用 RecAdd(tn1, item); } //循環添加全部的子文件到父節點下 foreach (string item in files) { //一樣的須要對絕對路徑作一下處理,提取文件名 string file = Path.GetFileNameWithoutExtension(item); TreeNode tn2= tn.Nodes.Add(file);//文件名添加到父節點下 tn2.Tag = item; //tag屬性石用來存儲程序員須要使用的任何數據 //把絕對路徑保存到剛添加的節點的tag屬性下,用於後面讀取文件裏的內容 } } private void tvwDir_AfterSelect(object sender, TreeViewEventArgs e) { TreeNode tn= e.Node ;//先獲取選中的節點 if (tn.Tag !=null)//判斷tag屬性是否是空 { txtContans.Text = File.ReadAllText(tn.Tag .ToString (),Encoding .Default ); } }
2、深拷與淺拷
拷就是拷貝、複製的意思
--》深拷和淺拷是指堆空間裏的對象和引用類型的拷貝,而值類型不存在深拷和淺拷,由於值類型只是把值給複製了一份。
淺拷
--》淺拷,只要有一個引用類型沒有被複制就是淺考,(複製就是產生了一個徹底沒有關係的對象,而這個對象裏德值是被複制過來的)
class Mark { string _name; public string Name { get { return _name; } set { _name = value; } } } class MyClass { string _name; Mark mark; public Mark Marks { get { return mark; } set { mark = value; } } public string Name { get { return _name; } set { _name = value; } } public MyClass Coby() { MyClass temp=new MyClass (); temp.Name = this.Name; temp.mark = new Mark(); temp.mark.Name = this.mark.Name; return temp; } } class Program { static void Main(string[] args) { MyClass m1 = new MyClass(); m1.Name = "張三"; m1.Marks = new Mark(); m1.Marks.Name = "哈哈哈"; MyClass m = m1; //這裏只是把m1的引用複製了一份賦給了m 並無複製m1裏的對象也沒有複製引用類型因此既不是深考也不是淺考 MyClass m2 = new MyClass(); //淺考 m2.Name = m1.Name; m2.Marks = m1.Marks;//這裏是把m1Marks裏的對象複製了,m1.marks存的引用又複製了一份賦給m2.marks此時他們都是指向了堆空間裏的另外一個對象mark,引用類型沒有被徹底複製在mark這裏斷開了,因此是淺考 MyClass m3 = new MyClass(); m3.Name = m1.Name; m3.Marks = new Mark(); m3.Marks.Name = m1.Marks.Name;//這裏m3是從新New一個對象,而後把m1.marks.name的值複製給m3.marks.name,他們是兩個徹底不同的對象,此時m1裏的引用類型被m3徹底的複製了一份,因此叫深考, //只要 全部的引用類型都被複制了沒有一個被斷開就是深考 }
1、序列化
爲何要序列化? --》爲了把內存裏的數據寫到硬盤裏。
序列化首先 第一步:給類加一個標籤,標記爲能夠被序列化,要序列化的對象類與父類均需標記
[Serializable] //標記 (特性的意思) Class myClass { } static void Main(string[] args) { #region 傳統方法 //Student stu = new Student(); //stu.Name = "張三"; //stu.Sex='男'; //stu.Age = 20; ////將student對象存到 //StringBuilder sb = new StringBuilder(); //sb.AppendLine(stu.Name ); //sb.AppendLine(stu.Age.ToString () ); //sb.AppendLine(stu.Sex .ToString ()); //File.WriteAllText("E:\\sb.txt", sb.ToString()); //string []input= File.ReadAllLines("E:\\sb.txt"); //Student s=new Student (); //s.Name = input[0]; //s.Age =Convert .ToInt32 ( input[1]); //s.Sex = Convert.ToChar(input[2]); #endregion List<Student> list = new List<Student>(); list.Add(new Student ("張三1",20,'男')); list.Add(new Student("張三2", 20, '男')); list.Add(new Student("張三3", 20, '男')); list.Add(new Student("張三4", 20, '男')); list.Add(new Student("張三5", 20, '男')); list.Add(new Student("張三6", 20, '男')); list.Add(new Student("張三7", 20, '男')); list.Add(new Student("張三8", 20, '男')); list.Add(new Student("張三9", 20, '男')); #region 榮譽代碼 //using (FileStream file = new FileStream("E:\\1.dat", FileMode.Create, FileAccess.Write)) //{ // BinaryFormatter bin = new BinaryFormatter(); // bin.Serialize(file, list); //} //Console.WriteLine("序列化完成"); //using (FileStream wfile = new FileStream("E:\\1.dat", FileMode.Open, FileAccess.Read)) //{ // BinaryFormatter bin=new BinaryFormatter (); // Student s = (Student)bin.Deserialize(wfile); //} #endregion //序列化 //首先須要一個寫得流 using (FileStream filewrite = new FileStream("E:\\1.dat", FileMode.Create, FileAccess.Write)) { //再須要一個工具 BinaryFormatter bin = new BinaryFormatter(); bin.Serialize(filewrite, list); //第一個是流,第二個是對象 } //反序列化 //首先也須要一個讀的流 using (FileStream fileread = new FileStream("E:\\1.dat", FileMode.Open, FileAccess.Read)) { //再須要一個工具 BinaryFormatter fbin = new BinaryFormatter(); List <Student > s = (List <Student >)fbin.Deserialize(fileread); } Console.WriteLine("完成"); }
序列化的一個應用---保存窗體上一次關閉時的位置
--》首先寫一個方法,保存窗體的位置(窗體的左上角的座標)和窗體的長和寬,在關閉窗體的時候調用這個方法。(寫在Dispose方法裏 關閉窗體時都會調用這個方法)
protected override void Dispose(bool disposing) { //調用保存窗體關閉時的位置大小 Save(); if (disposing && (components != null)) { components.Dispose(); } base.Dispose(disposing); --》而後要一個類,這個類裏面有兩個字段 來存儲窗體的location和size屬性,把這兒兩個屬性分別賦值給這個類的兩個字段 class MyPoint { Point mPoint; Size mySize; public Point MPoint { get; set; } public Size MySize { get; set; } }
--》而後序列化把數據寫到硬盤裏保存,當窗體關閉的時候調用這個方法就保存了窗體關閉時的位置和大小。
--》再寫一個方法反序列化,把存到硬盤裏德數據再拿出來,寫窗體的 Lode事件(窗體啓動前都會執行lode事件,lode事件通常都用來初始化),
把定義類的兩個字段裏存的數據再賦給窗體。
private void Save() {//須要一個流 using (FileStream filewrite = new FileStream("location.dat", FileMode.Create, FileAccess.Write)) { //new一個MyPoint類用來存儲窗體的位置大小 MyPoint mypoint = new MyPoint(); mypoint.MPoint = this.Location;//把窗體的位置賦給字段(窗體的左上角的point) mypoint.MySize = this.Size;//把窗體的大小賦給字段 //須要一個序列化的工具 BinaryFormatter bin = new BinaryFormatter(); //開始序列化 bin.Serialize(filewrite, mypoint); } } private void ReadLocatoin() { if (File.Exists("location.dat"))//判斷一下窗體的位置大小被改變了沒有,若是改變了會產生一個"location.dat"文件 { //須要一個流 using (FileStream fileread = new FileStream("location.dat", FileMode.Open, FileAccess.Read)) { //須要一個反序列化的工具 BinaryFormatter bin = new BinaryFormatter(); //開始反序列化 MyPoint p = (MyPoint)bin.Deserialize(fileread); //把窗體的啓動起始位置設置爲自定義 this.StartPosition = FormStartPosition.Manual; this.Location = p.MPoint; this.Size = p.MySize; } } } private void Form1_Load(object sender, EventArgs e) { ReadLocatoin(); }
//最近工做事情多,本系列下章應該會延時。