復習、
1、引用類型與值類型
--》文件的復制與快捷方式的復制
2、垃圾回收
3、靜態與非靜態
--》如何定義靜態成員與靜態類
--》如何調用靜態成員
4、異常
-》托管與非托管
-》.net frameworl
主要分為三個東西:CLR、CTS、類庫
-》由CLR管理的代碼就是托管的,否則就是費托管的(如File.Create)
->異常是一個類,需要拋出一個異常就要new
-》thorw關鍵字,拋出
二、常用類庫--String
大寫的String與小寫的string有什么不同?
-》可以說兩個都一樣
-》String是一個類
-》構造方法 new string(char [] shs)
2)兩個常用的屬性(Length/Empty(常量))
-》length 這一點與數組的用法類似
-》str[0]這個中括號就不叫下標,叫索引
常用的方法(索引的使用、ToCharArrray)
不可變性
既然是不可變的,那么多個字符串,結果相同的時候,就沒有必要每次生成一個對象(節省資源)
3)字符串拘留池(暫存池)
由于有字符串拘留池的存在,如果代碼中有大量的字符串的值相同,那么他們都指向同一個對象,
整個代碼中只創建一個對象。
字符串的內部實現與C語言的字符串的實現一樣,可以參考 IL Assembly這本書
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()
-》分割與合并
-》格式化
三、StringBuilder
->Appand() 追加
-》AppandLine 追加換行 相當于 Appand(“123/n”)
->AppandFramart 格式化
StringBuilder輸出的時候記得要ToString()一下
1)string.format 格式化字符串(就是挖坑填坑)
可以參考console.writeline(“{0}{1}”,str1,str2);不同的是conbsole.writeline()是輸出,Format是把它作為一個字符串返回。
-》@符號的兩個好處:1)可以取消轉義
2)寫字符串的時候可以換行
二、集合
為什么要有集合?
數組不是動態的,他的長度動態的變動,為了擬補這些就有了集合
可以認為,集合就是一個動態的數組,并且提供了一些處理的方法
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、1、2、3、4、5........那么就相當于一個ArrayList,那么可以得到結論,hashtable[鍵] 通過中括號 鍵來刪除。
三、泛型集合
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
二、foreach (可以遍歷任何實現了IEnumerble接口的對象)
foreach(臨時數據類型 臨時變量 in 要遍歷的集合)
{
//將臨時變量作為遍歷的數據使用
}
要知道臨時數據類型是什么類型的可以先寫個var 然后在下面設個斷點,再把光標放到var上去,就可以得到當前遍歷的集合是什么類型了
盡量不要用var
四、裝箱與拆箱
值類型轉換為引用類型就是裝箱
應用類型轉換為值類型就是拆箱
對值類型裝箱保持不變性,對引用類型不保持保持相關性()
Dotnet學習_遞歸篇
三、遞歸
遞歸就是調用自己
--》怎么調用?(遞推關系)
--》什么時候跳出
等差數列
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 ); } }
二、深拷與淺拷
拷就是拷貝、復制的意思
--》深拷和淺拷是指堆空間里的對象和引用類型的拷貝,而值類型不存在深拷和淺拷,因為值類型只是把值給復制了一份。
淺拷
--》淺拷,只要有一個引用類型沒有被復制就是淺考,(復制就是產生了一個完全沒有關系的對象,而這個對象里德值是被復制過來的)
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完全的復制了一份,所以叫深考, //只要 所有的引用類型都被復制了沒有一個被斷開就是深考 }
一、序列化
為什么要序列化? --》為了把內存里的數據寫到硬盤里。
序列化首先 第一步:給類加一個標簽,標記為可以被序列化,要序列化的對象類與父類均需標記
[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(); }
//最近工作事情多,本系列下章應該會延時。
新聞熱點
疑難解答