C# 高級特性總結


 
 
    • 待整理
      • 字典
        • 定義 Dictionary<string, string> openWith = new Dictionary<string, string>();
        • 添加元素 openWith.Add("dib", "paint.exe");
        • 取值 Console.WriteLine("For key = \"rtf\", value = {0}.", openWith["rtf"]);
        • 更改值 openWith["rtf"] = "winword.exe";
        • 遍歷key foreach (string key in openWith.Keys)
        • 遍歷value foreach (string value in openWith.Values)
        • 遍歷字典 foreach (KeyValuePair<string, string> kvp in openWith)
        • 添加存在的元素 catch (ArgumentException)
        • 刪除元素 openWith.Remove("doc");
        • 判斷鍵存在 if (openWith.ContainsKey("bmp")) // True
      • 數組
        • 1、數組[]特定類型、固定長度 string[] str1 = new string[3];
        • 2.二維數組 int[,] intArray = new int[2, 3];
        • 3多維數組 int[, ,] intArray1 = new int[,,]
        • 4. 交錯數組即數組的數組 int[][] intArray2 = new int[4][];intArray2[1] = new int[] { 2, 22 };
        • 常用:
          • Length屬性:所有維數中元素的總和
          • Rank屬性:表示數組中的維數
          • Sort方法:對一維數組排序,Array類的靜態方法 Array.Sort(name);
          • Reverse方法:反轉一維數組 Array.Reverse(name);
      • List
        • 創建
          • var intlist1 = new List<string>();
          • var intlist2 = new List<int>(){1,2,3};//創建了一個列表,里面的初始值有三個分別為 1 2 3
        • 添加元素
          • mList.Add("John");
          • string[] temArr = {"Ha","Hunter","Tom","Lily","Jay","Jim","Kuku","Locu"};mList.AddRange(temArr)
          • Insert(intindex, T item); //在index位置添加一個元素
        • 刪除元素
          • List. Remove(T item)
          • List. RemoveAt(intindex); //刪除下標為index的元素
          • List. RemoveRange(intindex,intcount); //從下標index開始,刪除count個元素
        • mList.Contains("Hunter")
        • List.Sort()
        • 給List里面元素順序反轉:List.Reverse ()
        • List清空  : List.Clear()
        • 獲得List中元素數目:List.Count()        //返回int值
        • if (coverWnds.Exists(p=>p.Index == strartNum))
        • add.Find(delegate(stup) { return p.Name == "abc" && p.age==15; });//使用委托
        • FindLastIndex、FindIndex、FindAll、Find
        • 兩個列表合並
          • listA.AddRange(listB );//把集合A.B合並
          • List<int> Result = listA.Union(listB).ToList<int>();          //剔除重復項
          • List<int> Result = listA.Concat(listB).ToList<int>();        //保留重復項
          • listA.BinarySearch("1");//判斷集合中是否包含某個值.如果包含則返回0
      • 元組
        • 創建
          • var ValueTuple = (1, 2); // 使用語法糖創建元組 ValueTuple
          • var tuple1 = new Tuple<int,int>(1,2);
          • var named = (first: 1, second: 2);
        • 取值
          • var u = unnamed.Item1;//1
          • var o = named.first;//1
        • 作為返回值
          • return new Tuple<int, int>(i, j);
      • String類型轉換成int
        • (1)  int.TryParse(string);
        • (2) Convert.Toint32(string);
        • (3) (int)string;
      • 文件讀寫
        • (一) 讀取文件
          • 如果你要讀取的文件內容不是很多,可以使用 File.ReadAllText(FilePath) 或指定編碼方式 File.ReadAllText(FilePath, Encoding)的方法。
          • 當文本的內容比較大時,我們就不要將文本內容一次讀完,而應該采用流(Stream)的方式來讀取內容。.Net為我們封裝了StreamReader類。初始化StreamReader類有很多種方式。下面我羅列出幾種
          • 假如我們需要一行一行的讀,將整個文本文件讀完,下面看一個完整的例子:
        • (二) 寫入文件
          • 寫文件和讀文件一樣,如果你要寫入的內容不是很多,可以使用File.WriteAllText方法來一次將內容全部寫如文件。如果你要將一個字符串的內容寫入文件,可以用File.WriteAllText(FilePath) 或指定編碼方式 File.WriteAllText(FilePath, Encoding)方法。
          • 當要寫入的內容比較多時,同樣也要使用流(Stream)的方式寫入。.Net封裝的類是StreamWriter。初始化StreamWriter類同樣有很多方式:
          • 同樣,StreamWriter對象使用完后,不要忘記關閉。sw.Close(); 最后來看一個完整的使用StreamWriter一次寫入一行的例子:
        • FileStream
          • 隨機文件讀寫
      • 格式化輸出
      • foreach(var xx in xxs)
        尤其用於字典 和Linq查詢結果的遍歷.
      • if(int .TryParse("9",out y))
      • 屬性Property和字段Field
        • 比較
          • 字段(成員變量)
            • a.字段主要是為類的內部做數據交互使用,字段一般是private。
            • b.字段可讀可寫。
            • c.當字段需要為外部提供數據的時候,請將字段封裝為屬性,而不是使用公有字段(public修飾符),這是面向對象思想所提倡的。
          • 屬性(方法)
            • a.屬性一般是向外提供數據,主要用來描述對象的靜態特征,所以,屬性一般是public。
            • b.屬性具備get和set方法,可以在方法里加入邏輯處理數據,靈活拓展使用。
        • 語法糖 自動屬性
          p.Name="小王";//為姓名屬性賦值。
      • yield return
        • 作用 : 在 return 時,保存當前函數的狀態,下次調用時繼續從當前位置處理。
        • 代碼:
        • 反面范例
        • 使用方法解析:這個函數在處理循環時可以每生成一個數據就返回一個數據讓主函數進行處理。在單線程的程序中,由於不需要等所有數據都處理好再返回,所以可以減少對內存占用。比如說有3個數據,如果一次性處理好返回,需要占用3個內存單位,而一個個返回,只需要占用1個內存單位。在多線程的處理程序中,還可以加快程序的處理速度。當數據處理以后,主程序可以進行處理,而被調用函數可以繼續處理一下個數據。一個經典的應用是Socket,主線程處理對Socket接收到的數據進行處理,而另外一個線程負責讀取Socket的內容。當接收的數據量比較大時,兩個線程可以加快處理速度。
      • 類和結構體的區別
        • ① 語法上的區別在於,定義類要使用關鍵詞class,而定義結構體則使用關鍵詞struct。
        • ② 結構體中不可對聲明字段進行初始化,但類可以。
        • ③ 如果沒有為類顯式地定義構造函數,c#編譯器會自動生成一個無參數的實例構造函數,稱之為隱式構造函數;
        • 與此不同的是,在結構體中,無論你是否顯式地定義了構造函數,隱式構造函數都是一直存在的。
        • ④ 結構體中不能顯式地定義無參數的構造函數,這也說明無參構造函數是一直存在的,所以不能在顯式地為結
        • 構體添加一個無參的構造函數;而類中則可以顯式地定義一個無參數的構造函數。
        • ⑤ 在結構體的構造函數中,必須要為結構體中的所有字段賦值。
        • ⑥ 創建結構體對象可以不使用new關鍵字,但此時結構體對象中的字段是沒有初始化值的,而類必須適應new關鍵詞來創建對象。
        • ⑦ 結構體不能繼承結構或者類,但可以實現接口;而類可以繼承類但不能繼承結構,它也可以實現接口。
        • ⑧ 類是引用類型,而結構體是值類型。
        • ⑨ 結構體不能定義析構函數,而類可以有析構函數。
        • ⑩ 不能用abstract和sealed關鍵字修飾結構體,而類可以。
      • foreach迭代器
        • 泛型
      • IComparable接口、IComparer接口和CompareTo(Object x)方法、Compare()方法
        list內元素的排序,我們一般使用 實現IComparable接口或者IComparer接口的方式來進行排序
        • 1.IComparable接口
          • 排序的條件只有一個時我使用IComparable接口進行排序
        • 2.IComparer接口
          • list.Sort(new AgeASC());
      • 反射
        • 0.獲取Type
        • 1.如何從一個字符串實例化一個類
          • Type type = Type.GetType("Person",true);
          • Person p = (Person)System.Activator.CreateInstance(type);
            使用Activator.CreateInstance(類型,構造函數對應個數的值);\用重載,其中一個重載,可以在t后面加上true,false(選擇是否只調用公共的構造函數)---true為可以調用private​
        • 2.如何通過一個字符串調用某個對象的某個方法
        • 3.通過屬性名稱字符串獲取某個對象的字段值
      • 方法簽名
        • 通過指定方法的訪問級別(例如 public 或private)、可選修飾符(例如abstract 或sealed)、返回值、名稱和任何方法參數,可以在類或 結構中聲明方法。這些部分統稱為方法的“簽名”。
        • 為進行方法重載,方法的返回類型不是方法簽名的一部分。
        • 但是,在確定委托和委托所指向方法之間的兼容性時,返回類型是方法簽名的一部分。
        • 委托是一種定義方法簽名的類型。
      • 集合類的聲明和初始化
      • using 釋放資源
      • var 類型推斷
      • 單問號和雙問號的使用
        • 兩個問號表示左邊的變量如果為 null 則值為右邊的變量,否則就是左邊的變量值,如:
      • 類型實例化
      • 擴展方法
      • 匿名類
      • Dynamic 相當於object
        Dynamic被編譯后,實際是一個object類型,只不過編譯器會對dynamic類型進行特殊處理,讓它在編譯期間不進行任何的類型檢查,而是將類型檢查放到了運行期
        • 定義數據
        • 使用
          • if (d is int)
          • d = (dynamic)i;
          • d = i as dynamic;
          • int i = d1;
      • Attribute
        • 特性(Attribute)是用於在運行時傳遞程序中各種元素(比如類、方法、結構、枚舉、組件等)的行為信息的聲明性標簽。您可以通過使用特性向程序添加聲明性信息。一個聲明性標簽是通過放置在它所應用的元素前面的方括號([ ])來描述的。
        • 特性(Attribute)用於添加元數據,如編譯器指令和注釋、描述、方法、類等其他信息。.Net 框架提供了兩種類型的特性:預定義特性和自定義特性。
        • [Obsolete("Don't use OldMethod, use NewMethod instead", true)]
          • 這個預定義特性標記了不應被使用的程序實體。它可以讓您通知編譯器丟棄某個特定的目標元素。例如,當一個新方法被用在一個類中,但是您仍然想要保持類中的舊方法,您可以通過顯示一個應該使用新方法,而不是舊方法的消息,來把它標記為 obsolete(過時的)。
        • [Conditional("DEBUG")]
          • 這個預定義特性標記了一個條件方法,其執行依賴於指定的預處理標識符。 它會引起方法調用的條件編譯,取決於指定的值,比如 Debug 或 Trace。例如,當調試代碼時顯示變量的值。
        • [AttributeUsage(AttributeTargets.Class | AttributeTargets.Constructor | AttributeTargets.Field | AttributeTargets.Method | AttributeTargets.Property, AllowMultiple = true)]
          • 預定義特性 AttributeUsage 描述了如何使用一個自定義特性類。它規定了特性可應用到的項目的類型。
      • 裝箱與拆箱
        • 裝箱 就是把“值類型”轉換成“引用類型”(Object);
          • 為何需要裝箱?
          • 類型不確定時,或者可以傳入任意類型時。
          • 調用一個含類型為Object的參數的方法,該Object可支持任意為型,以便通用。
          • 一個非泛型的容器,將元素類型定義為Object,以便通用。
        • 拆箱 就是把“引用類型”轉換成“值類型”;
        • 舉例
    • class 4
      • 正則表達式
        • 經常使用的類
          • Regex類,這是一個作用於匹配的類,用來定義一個匹配對象,即以何種規則進行匹配。
            • Match()方法:匹配出符合匹配要求的第一個結果,並返回一個Match匹配結果對象。
            • Matches()方法:匹配出符合匹配要求的所有結果,形成一個結果集,並返回一個MatchCollection匹配結果集對象
            • IsMatch()方法:進行匹配並返回一個布爾型代表是否有匹配的結果,有則返回true,無則返回false。
            • 以上三個方法的參數都是要被匹配的字符串,也可以是兩個參數,兩個參數的第一個參數依然是要匹配的字符串,第二個參數是匹配選項。(匹配選項是一個枚舉型,指定是否區分大小寫等。下面例舉一下匹配的選項。)
            • 注意:以上方法都有對應的靜態方法,靜態方法在這里就只說一個小例子,因為靜態方法和動態的方法差不多,只是靜態方法是將要匹配的字符串作為第一個參數傳入,第二個參數傳入參與匹配的正則表達式,第三個是可選參數,指定匹配模式。
            • RegexOptions選項的枚舉的常用值:
              • RegexOptions.IgnorePatternWhitespace:消除匹配正則中的所有非轉義空白。
              • RegexOptions.IgnoreCase:指定該正則表達式不區分大小寫。
              • RegexOptions.Multiline:多行模式,使用該模式會改變^和$的含義,^和$將不再是匹配字符串的開頭和結尾,而是匹配每行的開頭和結尾,系統默認的是單行模式。
              • RegexOptions.RightToLeft:匹配從右到左進行,而不是從左到右進行。
            • Split()方法:匹配出對應的字符串,並用這些字符串進行分割,返回的是一個string類型的數組。
            • Replace()方法:用指定的字符串替換字符串中符合匹配規則的子串,返回替換后的新字符串。
          • MatchCollection,這是一個作用於匹配結果集的類,因為既然涉及到匹配那么就可能會匹配出多個結果,這多個結果就可以賦值給匹配結果集(MatchCollection)的對象。
            • 對於MatchCollection類的常用屬性和方法我們經常用到的只有Count屬性。返回MatchCollection集合的Match對象個數,該屬性常用於查詢符合要求的匹配的個數。
          • Match,這是一個匹配結果的類,多個匹配結果(Match)組成一個匹配結果集(MatchCollection)。
            • 常用屬性:
              • Value屬性:匹配的的值。前面我們用Console.WriteLine(match);語句輸出的其實都是Value屬性的值。語句Console.WriteLine(match)等價於Console.WriteLine(match.Value)。
              • Groups屬性:該屬性是一個string類型的集合,保存匹配時候用小括號匹配的內容,用小括號匹配的內容用分組的形式儲存在了對應Match對象的Groups屬性中作為一個元素儲存了。我們可以通過Match對象.Groups[下標]的形式訪問分組的數據。
              • Length屬性:該屬性對應匹配到的子串的長度。
            • 常用方法:
              • Match類對象的常用方法只有一個:
              • NextMatch()方法。用來從前面的匹配的位置進行下一個匹配。
        • 舉例
        • 正則表達式的匹配規則
          • 1,正則表達式的通配符。
            • 1)"\d"這個符號代表從0-9的數字字符。
            • (2)"\w"代表所有單詞字符,包括:大小寫字母a-z、數字0-9、漢字(其實我認為是各國文字字符都可以但是身為中國人應該只用到了漢字)、下划線。
            • (3)"\s"代表任何空白字符,所謂空白字符就是打出來是空白的字符,包括:空格、制表符、換頁符、換行符、回車符等等。
            • (4)"\D"代表任何非數字字符。
            • (5)"\W"代表任何非單詞字符。
            • (6)"\S"代表任何非空白字符。
            • (7)"."代表除換行符(\n)之外的任何字符。
            • 注意
              • 第一:通配符"."因為代表除\n之外的所有字符,所以我們在匹配的時候如果要匹配到"."就應該用"\."代替,如上面我們匹配郵箱的案例,因為每個郵箱格式肯定是"XXX@XXX.com"里面有一個點,這個點我就用"\."代替了,而不是直接用"."。
              • 第二:既然我們所用的通配符都有"\"那么在定義正則規則的時候我們肯定要在正則規則字符串前面加@,以表示所有的\都不轉義。
              • 第三:正則表達式學起來非常容易,但是無論是幾年的程序員還是新手,寫正則表達式很容易出錯,這些錯誤筆者總結很大部分來源於通配符的使用,因為通配符實在是表示的范圍比較廣,我們沒有辦法掌握,所以在實際使用過程中應該盡量減少通配符的使用而使用我下面介紹的(可選字符集)形式。
          • 2,可選字符集
            • 案例一:[abc],指定這個字符位可以出現a或者b或者c。
            • 案例二:[123],指定這個字符位可以出現1或者2或者3。
            • 案例三:[a-d],指定這個字符位可以出現a到d的任何字符之一。
            • 案例四:[a-zA-Z],指定這個字符位可以出現大小寫字符的a-z
            • 案例五:[a-t1-7],指定這個字符位可以出現小寫字母a-t,數字1-7中的任何一個字符。
            • 案例六:[\w\s],指定這個字符位可以出現任何單字字符和任何空白字符之一。
            • 備注:所以所謂的可選字符集就是指定一個字符位可以出現哪個字符。
          • 3,反向字符集
            • 案例一:[^a],指定這個字符位可以出現除a之外的任何字符,注意是任何字符,不止是b-z。
            • 案例二:[^abc],指定這個字符位可以出現除小寫字母abc之外的任何字符之一。
            • 案例三:[^0-9],指定這個字符位可以出現除0到9之外的任何字符之一。
            • 案例四:[^#],指定這個字符位可以出現除井號之外的任何字符之一。
            • 案例五:[^\w],指定這個字符位可以出現除單詞字符之外的任何字符之一。
          • 4,“或”匹配
            或匹配用來匹配可以出現的某個字符串子串。
            • 案例一:thanyou|thankher,這個指定匹配出thankyou或者thankher。
            • 案例二:(b|tr)ee,這個指定匹配出bee或者tree。
            • 案例三:th(i|a)nk,這個指定匹配出thank或者think。
            • 案例四:book one|two,這個指定匹配出,book one或者two。注意不是book one或者book two。
            • 案例五:book (one|two),這個指定匹配出book one或者book two。
          • 5,限定符
            限定符用來限定字符(串)出現的次數。
            • "*"限定符:將前面的(一個字符)字符重復零次到多次。
              注意是一個字符:如我們用ds*對字符串進行匹配,匹配的是d后面跟0到n個s,而不是0到n個ds。
            • "+"限定符:將前面的(一個字符)字符重復一次到多次。
              注意:與*唯一的區別就是重復至少一次。
            • "?"限定符:將前面的(一個字符)重復零次到一次。
            • "{n}"限定符:將前面的字符重復n次。
            • "{n,}"限定符:將前面的字符重復至少n次。
            • "{n,m}"限定符:將前面的字符重復n到m次。
            • 補充
              • 限定符的懶惰修飾符,以上的限定符默認都是重復盡量多,而在以上的符號后面加"?"就重復盡量少。
              • 如:"*?"就是將前面的字符盡量少重復。
              • 案例一:我們用"5*?"去匹配字符串"25255255525555"匹配出來的結果是:空,因為*后面加了?,這樣的匹配規則就是匹配5零次到多次盡量少重復,這樣他當然就優先匹配出現零次,這樣匹配出來的結果全部是""。
              • 案例二:我們用"5*"去匹配字符串"25255255525555"的話匹配出來的結果不是這樣了,因為默認是盡量多重復,所以匹配出來的結果是:
              • 25、255、2555、25555。
          • 6,定位符
            定位符用來在正則規則中確定匹配對應的字符串的位置。
            • "^"定位符,^在定位符中代表匹配字符串的開頭位置,注意是開頭位置,不是字符串的第一個字符,可以理解為字符串第一個位置之前的小空隙。
            • "$"定位符,$定位符代表匹配字符串的末尾位置,可以理解為字符串最后一個字符末尾的空隙。
            • "\b"定位符,匹配單詞的邊界位置,也是空隙位置,單詞的空隙位置可以是:空格,逗號,句號,開頭,末尾,"-"等等。
            • 我們要匹配某個字符串開頭的四個字符組成的子串
              Regex regex=new Regex(@"^\w{4}");
          • 7,分組的概念
            • 在匹配郵箱的時候我們也可以使用分組的概念,比如,我們要一次將郵箱全址、郵箱用戶名都匹配出來,就可以用到分組的概念。
            • 此時匹配的正則表達式為:@"([a-zA-Z0-9_]+)@([a-zA-Z0-9])+\.com"。
            • 這個正則表達式我們用到了兩個括號,這兩個括號就是分組,將正則表達式分成了三組,第0組是整個匹配結果,第1組是第一個括號里面的內容,第二組是第二個括號里面的內容,顯而易見,第一個括號里面的內容是用戶名(即郵箱地址的@前面的字符串是用戶名)。
            • 這樣在匹配結果集的每個結果中都有可以通過訪問這些分組來訪問里面的數據,通過結果Match對象的Groups屬性進行訪問。
          • 8,非捕獲分組
            • "?:"此符號放在括號中代表非捕獲分組,意思是指定的括號不進行分組功能。
            • 比如在上面的匹配郵箱地址和郵箱用戶名的例子中我們希望括號里面不匹配到用戶名的話正則表達式就可以這樣改:
            • 正則表達式:@"(?:[a-zA-Z0-9_]+)@(?:[a-zA-Z0-9])+\.com
          • 9,"正向預查"和"負正向預查"
            • "?="正向預查:字符串后面的字符(串)進行限定。指定能夠出現的字符(串)。
            • "?!"負正向預查:對字符串后面的字符(串)進行限定,指定不能夠出現的字符(串)。
            • 在實際開發中比如我們有這樣的需求:在信息字符串"張三 性別:男 電話號碼:13699866695 李四 性別:女 電話號碼:13522693356 王五 性別:男 電話號碼:13859596459"中匹配出所有男性的姓名。
            • 根據上面的例子不難理解正向預查的概念,那么負正向預查也就自然而然的了解了,負正向預查就是限定匹配結果后面不能出現的字符串。
          • 10,"反向預查"和"負反向預查"
            • "?<="反向預查,限定匹配結果之前的字符串,(指定匹配結果之前的字符串必須是哪些)。
            • "?<!"負反像預查,限定匹配結果之前的字符串,(指定匹配結果之前的字符串必須不是哪些)。
            • 上面的需求如果我們進行修改,修改成匹配出所有性別為男的人的電話號碼,正向預查就解決不了這個問題了,因為正向預查是對匹配內容之后的內容進行限定,而我們要對匹配結果之前的內容進行限定的話就不行了。此時我們就需要用到反向預查的概念。
            • Regex regex=new Regex(@"(?<=性別:男\s+\b\w+\b:)\b\w+\b");
        • (.)/1+ replaced by $1
          去重
      • lambda
      • delegate
        • 定義  delegate void MyDelegate(string str,int index);
        • 實例化MyDelegate md = new MyDelegate(Show);
        • 多播代理
        • 預置
          • Func
            • Func至少0個參數,至多16個參數,根據返回值泛型返回。必須有返回值,不可void
          • Action
            • Action至少0個參數,至多16個參數,無返回值。
          • Predict
            •  Predicate有且只有一個參數,返回值固定為bool
            • Point first = Array.Find(points, ProductGT10);
            • var result = Array.FindAll(points, predicate);
            • StrList.Find , StrList.FindAll , StrList.Exists , StrList.FindLast , StrList.FindIndex
      • Event
        • 定義 public event CryHandler DuckCryEvent;
        • 事件訂閱DuckCryEvent +=new CryHandler(Cry);
    • class 5
      • Linq
        語句模式 /方法模式​
        • from n in xx where
        • 函數計算
        • 排序
        • Top(1)
        • 跳過前面多少條數據取余下的數據

          .Skip(10).Take(10) 分頁數據查詢
        • distinct()
          • list.distinct()比較的是getHash()方法
          • var distinctProduct = allProduct.Distinct(new ProductIdComparer());
        • 包含,類似like '%%'
        • 9.分組group by
        • sql中的In
        • 內連接 INNER JOIN
        • 左連接 LEFT JOIN
        • 盡量用方法而不是語句
    • class 6
      • 高級類型
        • var=>關鍵字 類型推導
        • dynamic =>動態類型,一種數據類型
        • tuple 元組
      • 多線程
        • Thread
          • 創建線程
            • 1.Thread類

              Thread thread2 = new Thread(new Program().myThreadMethod); Thread thread3 = new Thread(delegate() { Console.WriteLine("匿名委托"); }); ​Thread thread4 = new Thread(( ) => { Console.WriteLine("Lambda表達式"); });  為了區分不同的線程,還可以為Thread類的Name屬性賦值,代碼如下:Thread thread5 = new Thread(()=>{ Console.WriteLine(Thread.CurrentThread.Name); }); thread5.Name = "我的Lamdba"; ​​
            • 傳遞參數
              thread.Start("通過委托的參數傳值"); 要注意的是,如果使用的是不帶參數的委托,不能使用帶參數的Start方法運行線程,否則系統會拋出異常。但使用帶參數的委托,可以使用thread.Start()來運行線程,這時所傳遞的參數值為null。​
          • 常用函數
            • Thread.Sleep(2000);
            • Thread.CurrentThread.ManagedThreadId.ToString() 
            • 線程同步
          • 前台線程:主程序必須等待線程執行完畢后才可退出程序。Thread默認為前台線程,也可以設置為后台線程
          • 阻塞主線程
        • 線程池ThreadPool
          當處理單個任務時間較短或者需要處理的任務數量比較大的時候要考慮使用線程池
          • 可以看到,上段代碼沒有顯式創建線程,而是把方法放到了ThreadPool.QueueUserWorkItem()方法中,ThreadPool負責創建和管理線程。當程序剛開始時,ThreadPool第一次被調用,這時線程池里一個線程沒有,線程池會創建一個新線程,當程序再次調用線程池時,若線程池忠還有空閑線程,則直接調用空閑線程執行程序;若程序調用線程池時,線程池中沒有空閑線程且CPU處於“未飽和”狀態,則線程池會創建新線程。實際上,當調用線程池時,相當於把要執行的方法“掛”在線程池的任務隊列上,當CPU處於“未飽和”狀態,線程池就會調用線程來執行線程池任務隊列中的任務。
        • Task
          • 都是后台線程,后台線程:主程序執行完畢后就退出,不管線程是否執行完畢。ThreadPool默認為后台線程
          • 線程號可能是一樣的,會回收,實際上內部維護了一個線程池
          • Task參數
            • Task<Int32>   task = Task.Run(() => fun("s", 9));
          • Task的返回值
            • Task<int> t=xxx;t.Reslut
            • task對於有返回值的工作函數可以通過訪問其Result函數來實現阻塞等待。
          • Task有參數有返回值
          • Task三種創建方式
            • Task t2 = new Task(() => {Console.WriteLine("開啟一個新任務");});t2.Start();
            • ​Task t = Task.Factory.StartNew(() => {Console.WriteLine("任務已啟動....");});
            • Task.run(() => {Console.WriteLine("任務已啟動....");})
              •  Run(Action) 
          • 三種創建方式的區別
            •  首先我們說Task.Run和StartNew的區別:
              • 1、Task.Run它是將在線程池上運行的指定工作排隊,它默認的任務計划(TaskScheduler)是線程池,並且不允許修改任務計划。而StartNew是可以指定任務計划的。
              • 2、Run是TaskFactory.StartNew的輕量級實現。Run方法是啟動計算密集型任務的建議的方法,StartNew方法僅在需要精細地控制長時間運行的計算密集型任務時使用,這一點應該是這兩者最重要的區別了。
              • 3、Run方法無法為委托傳遞輸入參數,而StartNew可以。
            •    再說一下Run和Start的區別:
              • 1、start的重載函數只有2個,一個是在當前的任務計划中執行,一個是指定計划任務執行。其他的參數在Task的構造函數中設置。這個當前的任務計划指的是當前上下文所在的任務計划。
              • 2、Start任務可以啟動和僅運行一次。 第二次計划的任務的任何嘗試都將導致異常。
              • 3、Run是一個靜態方法,Start是一個實例方法。
              •  綜上所述,微軟推薦的創建線程的方法是Run方法,但是我們需要根據自己的需求選擇合適的方法。
          •  the parameters and meaning of the factory method
            •  Action,Func等參數與Run()相似,只是在重載函數里增加了一個TaskCreationOptions 枚舉參數,指定可控制任務的創建和執行的可選行為的標志。
            • 常用:LongRunning,指定任務將是長時間運行的、粗粒度的操作,涉及比細化的系統更少、更大的組件
          • Task的常用方法
            • t.wait()
            • Task.WaitAll(t1,t2)
            • Task.WaitAny()
            • t1.ContinueWith(t2)
              • 返回值:Task<TResult>,可以通過多種方式創建實例。 最常見的方法是調用靜態Task.Run<TResult>(Func<TResult>)或Task.Run<TResult>(Func<TResult>, CancellationToken)方法
              • Task<int>.Factory.StartNew(() => negate(6)).ContinueWith(antecendent => action("x")) .ContinueWith(antecendent => negate(7)) .Wait();
        • 三者區別
          • 首先說Thread、ThreadPool
            • 前台線程:主程序必須等待線程執行完畢后才可退出程序。Thread默認為前台線程,也可以設置為后台線程
            • 后台線程:主程序執行完畢后就退出,不管線程是否執行完畢。ThreadPool默認為后台線程
              Net環境使用Thread建立的線程默認情況下是前台線程,即線程屬性IsBackground=false,在進程中,只要有一個前台線程未退出,進程就不會終止。主線程就是一個前台線程。而后台線程不管線程是否結束,只要所有的前台線程都退出(包括正常退出和異常退出)后,進程就會自動終止。
            • 線程消耗:開啟一個新線程,線程不做任何操作,都要消耗1M左右的內存
            • ThreadPool為線程池,其目的就是為了減少開啟新線程的消耗(使用線程池中的空閑線程,不必再開啟新線程),以及統一管理線程(線程池中的線程執行完畢后,回歸到線程池中,等待新任務)
            • 總結:ThreadPool性能會好於Thread,但是ThreadPool與Thread對線程的控制都不是很夠,例如線程等待(線程執行一段時間無響應后,直接停止線程,釋放資源,兩者都沒有直接的API,只能通過硬編碼實現)。同時ThreadPool使用的是線程池全局隊列,全局隊列中的線程,依舊會存在競爭共享資源的情況,從而影響性能。
            • 下面說Task
          • Task背后的實現,也是使用的是線程池線程。但是它的性能優於ThreadPool,因為它使用的不是線程池的全局隊列,而是使用的是本地隊列。是的線程之間競爭資源的情況減少。
            • Task提供了豐富的API,開發者可對Task進行多種管理,控制。
        • 同步和互斥
      • 泛型
      • async/await
        異步方法:一個程序調用某個方法,在處理完成之前就返回該方法。通過 async/await 我們就可以實現這種類型的方法。
        • 用法:
          • Async 方法有三種可能的返回類型: Task、Task<T> 和 void
          • async Task MyMethodAsync() {return t;}自動封包
            • async的函數本質上只是包裝,與手動返回Task並沒有實質區別(Task.ContinueWith(xxxx))。
            • 一個返回Task<int>的函數,不只可以用來await,還有很多別的玩法,語言應該給予開發人員解開和不解開的自由
          • await task;自動解包
          • async函數用法:
            • Task<T> t=asyncfun() t.Result阻塞!
        • 解釋
          • 在await之前,都是同步執行,await開始才是異步執行,記錄阻塞點1,返回async函數的調用點
          • await並不創建線程,只有Task會創建線程
          • await相當於await東西的回調函數
          • async只是為了標記await存在,所以二者總是同步出現,單獨的async不起作用
        • 實例
    • 作業題
      • 作業1.統計字頻
      • 作業2
        • 最小值
        • 去重
      • 作業3 至少有一個6分
        • 老師
      • 作業4 三種創建Task的方式
      • 作業5
        • 1.類的繼承、多態
        • 2.迭代器
        • 3.比較
      • 作業6
        • 事件訂閱
        • 反射


免責聲明!

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



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