2018.8.14-C#复习笔记总
生活随笔
收集整理的這篇文章主要介紹了
2018.8.14-C#复习笔记总
小編覺得挺不錯的,現在分享給大家,幫大家做個參考.
2018.8.14-C#復習筆記總
using System; using System.Collections.Generic; //using System.Linq; using System.Text; using System.Diagnostics; using System.IO; using static System.Console; using System.Linq; using System.Runtime.InteropServices; using System.Threading; using System.Text.RegularExpressions; using System.Threading.Tasks; using System.Security.Permissions; using System.Net.Sockets; using System.Net;namespace ConsoleApplication1 {class Program{[DllImport("dltest.dll", EntryPoint ="Print")]static extern void xPrint(int x);#region old-test// static void TestStreamReadWrite(){//一個流不能兼備讀寫兩種操作,不知道為什么,這不合理string s1 = "你好啊ABC";var t = "你好啊ABC".Length;//關于編碼注意幾點://1,sizeof(char) 等于 2//2,str.Length 是以元素個數算的,不是按字節算的,如 "你好啊ABC” length = 6//3,c#在VS的默認編碼為 Encoding.Default, 該編碼下漢字占兩字節,非漢字占1字節,通過查看ms中的字節數據可知//4,string 類型寫入任何buffer時都是先寫長度,一般為1字節,再寫字節數據,如下var sz = sizeof(char); //2, 注意char占2字節var szb = sizeof(bool); //1var ms = new MemoryStream();var writer = new BinaryWriter(ms, Encoding.UTF7);writer.Write(s1);ms.Close();writer.Close();var ms2 = new MemoryStream(ms.GetBuffer());var reader = new BinaryReader(ms2, Encoding.UTF8);var s2 = reader.ReadString();}// static void TestEncoding(){string s1 = "你好啊ABC";//漢字亂碼問題,漢字必須使用2個以上字節才能表示//編碼方式//1,ASCII碼,只有一個字節,不能正確表示漢字,出現亂碼,可以正確表示數字和字母符號//2,UNICODE,任何符號都用2個字節表示,因此可以表示漢字和任意符號//3,UTF8,變字節的編碼,可以正確表示任何字符和漢字,各國語言//4,GB2312編碼,國標碼,主要是為漢字服務的中國編碼,漢字占兩字節,字母數字占1字節//5,default編碼,在國內, 般就是GB2312 Encoding.Default.GetBytes(s1);var bytes = Encoding.GetEncoding("GB2312").GetBytes(s1);var len = bytes.Length;var bts = new byte[10 + len];Array.ConstrainedCopy(bytes, 0, bts, 0, len);var s2 = Encoding.GetEncoding("GB2312").GetString(bts).TrimEnd('\0');string s3 = "\0hello/0/0dddddd".TrimStart('\0');//!!!!!!!!!!!!!!!!!!!!!!!!!!!! }#region 計算機中數據的存儲// static void TestTypeConvert(){//把一個有符號數轉為無符號后再轉回來值保持不變,以下以1字節為例//原理:計算機中符點數都是有符號的,不存在這種轉變,只剩下整數,//真值:絕對值的二進制值,如-1的真值為 00000001//整數是以補碼形式存放的,計算機規定了正數的補碼是本身,負數的補碼是:符號位不變,真值按位取反再加1//強制轉換做的事就是把一個補碼看成是有符號還是無符號//有符號數,在計算時:符號位不變,真值按位取反再加1。無符號數直接計算,舉例如下://1,-1 的真值為00000001,補碼為 1 111 1111,強轉時就是把補碼值看作是一個無符數,因此它=255//,再次強轉時把它看成有符號數,符號位不管,其余位按位取反加1后是1,因此再次轉回了-1//2,-2 的真值為00000010,補碼為 1 111 1110,強轉時把補碼看作無符號數,因此它=254//3,-128真值有點特殊,128的二進制碼為1000 0000,第8位是符號位,舍棄,取后面的0,即-128的真值為0//補碼經按位取反加1后還是 1 000 0000,強轉時看成無符號數即為128//-------------------------------------------//1字節數據和2字節數據進行加法運算時,要進行位擴展,將1字節擴展為2字節//正數擴展時高位補0,負數擴展時高位補1//C#中小于4字節的數據進行運算時會先擴展成int再進行sbyte sb = -127;var b = (byte)(sb);var sb1 = (sbyte)(b);object dx = 10.0f;double dx2 = 33;byte ix = (byte)dx2;var t = dx.GetType();Type T = System.Type.GetType(t.FullName, true);}#endregion// void TestUncheck(){unchecked{//不被編譯系統做編譯時安全檢查 }}static void TestBoxing(){int i = 10;object o = 1;int i2 = (int)o;}static void TestReadBytes(){byte[] bts = new byte[4] { 23, 0, 16, 0 };var ms = new MemoryStream(bts);var br = new BinaryReader(ms);var p1 = ms.Position;var ix = br.ReadUInt32();var p2 = ms.Position;Console.WriteLine("num=" + ix);br.Dispose();br.Close();ms.Dispose();ms.Close();}static void TestStrEnd(){string str = "abcde\0";var br = new BinaryReader(new MemoryStream(Encoding.ASCII.GetBytes(str)));var b = br.ReadByte();while (b != 0){Console.WriteLine(b);try{b = br.ReadByte();}catch (System.Exception ex){Console.WriteLine("未發現字符串結束符");break;}}}static void TestBigEndia(){var br = new BinaryWriter(File.Create("f:/testx.dt"), Encoding.ASCII);br.Write((Int16)9);string str = "Stand";br.Write(str);br.Write((Int16)10);br.Write((Int16)70);br.Dispose();}static void TestChar0(){//注意字符串中0和\0的區別,如 s1="h0ello", s2 = "h\0ello"//s2中的\0是字符串結尾符,除了C#不把它作為結束符外,其它語言都把它作為結束符,如U3D,LUA,C/C++等//而s1中的0僅是一個字符0而已,字符0的ASCII值是0X31=49,'\0'的ASCII值是0//注意這兩種0在C#和U3D的API之間切換時容易造成BUG,如://1, debug.log(s1): "h0ello"//2,debug.log(s2): "h"var s = "hello";s += 0 + ",world";var s1 = "hello";s1 += (char)0 + ",world";var s2 = "hello";s2 += '\0' + ",world";}static void MemTest(){}static void ReflectionTest(){//測試兩種反射的效率問題//Type.GetType()只能在同一個程序集中使用,typeof則可以跨程序集(assembly)//通過下面的實測,發現typeof是比GetType快40多倍var timer = Stopwatch.StartNew();timer.Start();Type tx = Type.GetType("string");var tx1 = Type.GetType("float");timer.Stop();Console.WriteLine("T1= " + timer.Elapsed);//0.0000471 timer.Restart();tx = typeof(string);tx1 = typeof(float);timer.Stop();Console.WriteLine("T2= " + timer.Elapsed);//0.0000011 }static void TestDelegate(){//類C++11風格:指定初始化容量20,使用初始化列表給部分成員賦值var lst = new List<float>(20) { 1, 3, 4, 20, -2, 9, 0 };for (var i = 0; i < lst.Count; ++i){//使用下標進行隨機訪問,說明list不是一個真正的鏈表,而是類似STL的Vector Console.WriteLine(lst[i]);}//public void Sort (Comparison<T> comparison) //public delegate int Comparison<T>(T x, T y);//這是對調用List<int>.Sort進行排序的寫法,其中sort的定義及Comparison委托的定義如上lst.Sort(new Comparison<float>(delegate (float m1, float m2) //委托 {return 1;}));lst.Sort(delegate (float m1, float m2) //委托 {return 1;});lst.Sort((float m1, float m2) =>//Linq表達式 {return 1;});lst.Sort((m1, m2) => //Linq表達式 {return 1;});}static string TestRetStr(){//測試返回字符串是否會復制return "helloworld";}static void TestStrRet(){//h1 = h2 = h3說明它們返回的是同一個字符串的引用var s1 = TestRetStr();var s2 = TestRetStr();var s3 = TestRetStr();var h1 = s1.GetHashCode();var h2 = s1.GetHashCode();var h3 = s1.GetHashCode();}static void TestVirtualFuncCall(){var otx = new CTestChildX();otx.Update();//輸出結果:child,如果注釋1處函數不加override,輸出結果為:basevar oty = new CTestY();oty.Update();oty.OnUpdate();}static void TestStrModify(){var s1 = "hello";var s2 = s1;s1 += "world";Console.WriteLine(s2);var uns1 = s2.GetHashCode();Console.WriteLine(uns1);}static void Tests1(){var s1 = "hello";var uns1 = s1.GetHashCode();Console.WriteLine(uns1);}#endregion#region 2018.3.30#region ref out and templateclass myTemp<T1, T2>//類入口 {public T1 Add(T1 a, T1 b){//模板類型不能直接相加,必須先轉為動態類型,避開編譯檢查,運行時動態決定類型dynamic da = a;dynamic db = b;return da + db;}public void tint<T3>()//注意C++不能這么寫,所有模板參數必須由類入口傳入 {Type t = typeof(T3);WriteLine(t);}}delegate void refOutFunc(ref double t1, out double t2);delegate T TemplateDelegate<T, U>(T a, U b);static void TestRefAndOut(){//ref, out 本質上都是引用//fef就為了傳給函數使用,必須先初始化,但也可以傳出數據,out是為了從函數中傳出數據使用,不用初始化refOutFunc rof = delegate (ref double ax, out double bx) {ax = 1; bx = 2;//ref out兩種類型的變量都被更改了 };double x1 = 0, x2;rof(ref x1, out x2);}static void TestTemplate(){var otp = new myTemp<int, int>();otp.tint<object>();}static T TempFunc<T, U>(T a, U b){return a;}static void TestBufAligin(){//自定義字節BUF的對齊測試int x = 9;int y = (x + 7) & ~7;WriteLine(y);}#endregion#endregion#region 2018.4.9//BUG??????//使用StopWatch測試運行時間//兩段測試A和B//測試結果受測試順序影響,后測要比先測耗時長了許多static void TestKeyIntStr(){// var idict = new Dictionary<int, string>();var sdict = new Dictionary<string, string>();for (int i = 0; i < 1000000; i++){var key = i * 2 + 1;var v = i * i + "";idict.Add(key, v);sdict.Add(key + "", v);}//測試 Avar t1 = 100000 * Test1(idict);//測試 Bvar t2 = 100000 * Test2(sdict);Console.WriteLine("t1: {0},t2: {1}", t1, t2);//Console.WriteLine("dt1: {0},dt2: {1}", dt1, dt2); }static float Test1(Dictionary<int, string> dict){var timer = new Stopwatch();timer.Start();var it = dict[2001];var t1 = timer.ElapsedTicks;timer.Stop();return (float)((float)t1 / Stopwatch.Frequency);}static double Test2(Dictionary<string, string> dict){var timer = new Stopwatch();timer.Start();var it = dict["2001"];var t1 = timer.ElapsedTicks;timer.Stop();return (float)((float)t1 / Stopwatch.Frequency);}#endregion#region 2018.7.7#region 數組的數組,二維數組static int[] returnArray(){//數組是引用類型,分配在堆上int[] arr = { 1, 2, 3, 4 }; //雖然這樣寫,其實等價于int[] arr = new int[]{1,2,3,4};return arr; //返回一個數組對象 }static void TestArray() {//1,一維數組char[] arr = new char[2] { 'a', 'b' }; //必須全部初始化,或不初始化int[] iarr = new int[2] { 0, 1 };char[] sarr = new char[3];//2,數組的數組,鋸齒數組char[][] d2arr = new char[2][];d2arr[0] = new char[30];d2arr[1] = new char[2] { 'a', 'b' };d2arr[0][1] = 'x';//3,二維數組,矩陣int[,] i2arr = new int[2, 3];for (var i = 0; i < 2; ++i){for (var j = 0; j < 3; ++j){i2arr[i, j] = i * 3 + j;}}}#endregion#region 字段初始化無法使用非靜態(字段、方法、屬性)delegate int mydelegate(int x);//-------------------------------------------------------------------------//字段初始化無法使用非靜態(字段、方法、屬性)//-------------------------------------------------------------------------float fxs;static float sfxs;//float fxs2 = fxs; //errorfloat fxs3 = sfxs; //right,可用靜態字段初始化float fxs4 = TestStaticInit(); //right,調用靜態函數初始化static int TestStaticInit() { return 10; }mydelegate _mydel = (x) =>//LINQ為什么可以?,從下面可知,LINQ語句只相當于一堆初始化語句的集合 {//int fx = fxs; //errorreturn 20;};#endregion#region 默認訪問修飾符//1,名字空間中,最外層類及接口的默認修飾符為internal,也就是本程序集可訪問//2,類中,變量,成員,類中類的默認修飾符為private//3,結構中,同類//4,接口中,所有方法和屬性都為public,接口中只能有方法,不能有變量interface IMyinterface{//接口中可以有方法,抽象屬性,不可以有變量int Id { get; } //抽象屬性,公有void Fly(); //方法,公有 }#endregion#region 類模板繼承class CTClass<t1, t2, t3> //多個where的寫法where t1 : struct //必須是值類型where t2 : class //必須是引用類型where t3 : new() //必須有無參構造函數 {float fx, fy;public static t1 Add(t1 a, t1 b){return (dynamic)a + (dynamic)b;}}//模板繼承的幾種方式//1,全特化class CDTClass : CTClass<int, CCmpBase, CCmpBase> { }//2,原樣繼承,注意基類的所有約束都要重寫一遍class CDTX<t1, t2, t3, t4> : CTClass<t1, t2, t3>where t1 : struct //必須是值類型where t2 : class //必須是引用類型where t3 : new() //必須有無參構造函數 { }//3,偏特化,介于二者之間的形態#endregion#region 運算符重載class CCmpBase{//帶有默認構造函數float _x;}class CComplex : CCmpBase{float real, image;public CComplex(float real, float image = 0){this.real = real;this.image = image;}//一,類型轉換 :數值轉對象//CComplex cp = 2.1f 或 CComplex cp; cp = 2.1f;//C#從不調用類型轉換構造函數進行類型轉換public static implicit operator CComplex(float real){return new CComplex(real);}//二,類型轉換:對象轉boolpublic static explicit operator bool(CComplex cp){return cp.real != 0 && cp.image != 0;}//三,類型轉換:對象轉數值public static implicit operator float(CComplex cp){return cp.real;}//四,算術運算符重載 : +,-,*,/,%等//c#的運算符重載全部為靜態函數,因此沒有隱含參數//而C++運算符重載時可以重載為友元,絕大多數重載為類的成員函數,因此基本都有一個隱含參數(對象本身)public static CComplex operator +(CComplex a, CComplex b){return new CComplex(a.real + b.real, a.image + b.image);}public static CComplex operator ++(CComplex cp){cp.real++;cp.image++;return cp;}//五,不支持的運算符重載//1,不允許重載=運算符, C++可以,都不允許重載+=之類的//2,不允許重載括號()運算符//3,不允許重載[]運算符,因為它是索引器//public static implicit operator () (CComplex cp)//{// return a;//}void TestPrivate(){var cp = new CComplex(1, 3);cp.real = 20;cp.image = 30.0f;}public void PrintInfo(){WriteLine("real:{0},image:{1}", real, image);}}static void TestOperatorOverload(){CComplex cp = new CComplex(1, 1);//1,同時支持前后向++,【不同于C++】cp++;++cp;//2,但不允許連++, 【不同于C++】//cp++++或 ++++cp cp.PrintInfo();//3,支持連續+,【同于C++】CComplex cp1 = new CComplex(1, 1);var cpadd = cp + cp1 + cp1 + cp1;cpadd.PrintInfo();//類型轉換運算符cp = 2.1f;//類型轉換運算符//C++中是調用類型轉換構造函數,而不是運算符重載CComplex cp2 = 1.0f;}#endregion#endregion#region 2018.7.11#region 兩數相加函數模板實現static T MaxNum<T>(T a, T b){return ((dynamic)a > (dynamic)b) ? a : b;}#endregion#region thread lock//thread testclass Account{private object thisLock = new object();int balance;Random r = new Random();public Account(int initial){balance = initial;}int Withdraw(int amount){if (balance < 0){throw new Exception("Negative Balance");}lock (thisLock){if (balance > amount){WriteLine("before-withdraw: " + balance);WriteLine("amount to withdraw: " + amount);balance -= amount;WriteLine("after withdraw: " + balance);return amount;}elsereturn 0; //transaction rejected }}public void DoTransactions(){for (int i = 0; i < 100; ++i){Withdraw(r.Next(1, 100));}}}static void TestObjectLock(){Account acc = new Account(1000);Thread[] threads = new Thread[10];for (int i = 0; i < 10; ++i){threads[i] = new Thread(acc.DoTransactions);}for (int i = 0; i < 10; ++i){threads[i].Start();//threads[i].Join(); }}#endregion#region derive protectedclass A{float fxPrivate;protected int nProtected;protected A(int x) { }}class B : A //c++的公有繼承 {B(String name, int x) : base(x) { }protected int nProtected;void TestDerive(){//這里的規則與C++完全一樣://1,子類不能訪問基類的私有成員,可以訪問基類的保護和公有成員//2,保護成員可以在本類中訪問(不一定是本對象中)nProtected = 20;base.nProtected = 10;var ob = new B("b", 1);ob.nProtected = 30; //類中訪問類的保護成員,但不是本對象的成員 }}#endregion#endregion#region 2018.7.12#region 常量和靜態變量靜態類readonly//----------------------------------------------------------------------//常量和靜態變量,靜態類//----------------------------------------------------------------------//類的靜態變量和常量,都屬于類而不屬于對象,不能用對象來調用,只能用類名調用//這不同于C++,是更合理的設計//常量的值在類定義時就確定了,不因對象而不同,因此存放在類中更合理class CNormclass{class CInclass{public float fx = 20;}public int _id;public const string cname = "CNormalclass";//1,常量僅能修飾 :數字,bool,字符串,null引用//不能像C++那樣定義一個常量對象,這真是太悲哀了,因為很多時候這可以加速數據傳遞,增加安全性//由于這個原因,C#的List.ToArray每次都只能返回一個內部數組的拷貝,因此使用list存儲數量較大較復雜的數據時//不要輕易使用ToArray,直接用List就行了,它也支持下標索引方式取數組元素const CInclass lst = null;//2,readonly也不能實現常量對象的效果//readonly僅表示變量本身不能被賦值,但不阻止通過對象變量更改對象內的字段//onc.readonlyobj.fx = 20public float fx = 20;private readonly CInclass readonlyobj = new CInclass();public void FuncX() { }//3, 屬性不能用readonly修飾virtual public int ReadonlyProp {//4,屬性可以為虛private set; //可以加限定符get;}public static void Test(){//1,不能調用非靜態字段或方法//this._id = 20; //error,沒有this指針//2,可以調用常量字段var lname = cname;var onc = new CNormclass();//私有變量在類的靜態方法也可以訪問//2,雖然不能更改readonlyobj本身的值,卻可以更改其內部成員的值,這就是readonly的作用onc.readonlyobj.fx = 20; }}static class C712//類中類,默認為私有{//靜態類不能實例化,且只能聲明:常量,靜態常量,靜態屬性,靜態方法public const int constX = 20; //1,常量public static int staticX = 0; //2,靜態常量public static int ix { set; get; } //3,靜態屬性//一,【靜態類中不能定義實例化字段】//public int _id; //二,【靜態類中不能定義實例化字段】//void Ctest(){ //【error: 靜態類中不能定義實例化方法】// this._id = 20;//}static void Test()//4,靜態方法 {//三,【靜態方法中不能調用非靜態變量或方法,因為沒有this指針】//_id = 20; //error //四,【可以調用常量字段,這與C++不同】var c = constX;}}public const int ixd = 20;public static float fx = 20;public void Testff(){fx = 30; //等價于Program.fx = 30,而不是 this.fx = 30;Program.fx = 30;var tx = C712.constX;C712.staticX = 30;var ix = Program.ixd;//var oc7 = new C712(); //error 靜態類不能創建實例 }#endregion#region 事件和委托//--------------------------------------------------------------//event -test//--------------------------------------------------------------//使用event的好處,與delegate的區別://event 本質上是一個委托,是做了一些安全措施的委托//1,event 定義的委托只允許 +=操作,不允許=賦值,這樣防止事件被誤清空,delegate則沒有這些限制//2,event 定義的委托只能在本類中調用,可以防止外部觸發,delegate沒有這些限制//3,不使用事件,delegate方式完全可以實現類似限制,通過私有變量和公有函數結合方式class EventTest{public delegate void Delx(string s = "");Delx _delegate; // 私有委托,防止外部調用public event Delx _event; //公有事件,給外部通過+=注冊使用,但_event()函數只能在本類調用,不能在類外調用//-------------------------------------------------------------//1 ,委托方式//-------------------------------------------------------------//(1)外部調用eventTest.AddListener(func)方式注冊事件public void AddListener(Delx callback){_delegate += callback;}//(2)本類對象調用此函數觸發事件void DelegateBrocast(){_delegate("delegate"); //回調,觸發事件 }//-------------------------------------------------------------//2,事件方式//-------------------------------------------------------------//(1)外部使用 _event += 方式注冊回調函數//(2)本類對象調用此函數觸發事件void EventBrocast(){_event("event");//回調,觸發事件 }}class Listener{public void OnEvent(string s){WriteLine("on-event---------------" + s);}}static void TestEventAndDelegate(){Listener l1 = new Listener();EventTest test = new EventTest();//1,事件方式test._event += l1.OnEvent; //注冊事件//test._event = l1.OnEvent; //編譯錯誤,事件只能使用+=,防止事件被清空//test._event("event"); //編譯錯誤,事件不能在類外調用,事件只能由其所在類調用//2,委托方式test.AddListener(l1.OnEvent); //注冊委托,通過函數對委托進行注冊,因委托是私有的,可防止直接操作 test._delegate() }#endregion#region 文件和目錄static void FileAndDirectory(){//-------------------------------------------------------------------------//文件對象的相關操作//-------------------------------------------------------------------------//方式一,使用工具類:File類,不需生成對象var file = File.Open("f:/test.txt", FileMode.Create, FileAccess.ReadWrite);//方式二,通過FileStream的對象var filestream = new FileStream("f:/test._txt", FileMode.Create, FileAccess.ReadWrite);//-------------------------------------------------------------------------//目錄文件相關操作//-------------------------------------------------------------------------//方式一,實例化DirectoryInfo類var dir = new DirectoryInfo("f:/tolua");//(1)獲取目錄foreach (var d in dir.GetDirectories("*.*", SearchOption.AllDirectories)){WriteLine(d.FullName);}//(2)獲取文件foreach (var fileinfo in dir.GetFiles("*.*", SearchOption.AllDirectories)){WriteLine(fileinfo.FullName);}//方式二,使用工具類: Directory類,不需生成對象//(1)獲取目錄var dirs = Directory.GetDirectories("f:/tolua", "*.*", SearchOption.AllDirectories);//(2)獲取文件dirs = Directory.GetFiles("f:/tolua", "*.*", SearchOption.AllDirectories);for (int i = 0; i < dirs.Length; ++i){//打印輸出 WriteLine(dirs[i]);}}#endregion#endregion#region 2018.7.17#region 計算機中浮點數的存儲static void TestFloat(){using (var ms = new MemoryStream()){using (var br = new BinaryWriter(ms)){br.Write(125.5f);var bytes = ms.GetBuffer();}}unsafe{float fx = 125.5f;int* pfx = (int*)(&fx);}}#endregion#region 位移運算static void TestBitShift(){ //----------------------------------------------------------------------------//十進制數轉二進制://1,原理:將數X右移1位,最低位被移出,再左移,得到了數X0,則x-x0即為最低位的值//2,手工算法:根據1的原理,不斷的對一個數整除2得余數,了終得到余數序列即是二進制的反向序列//3,左移等價于乘2,右移等價于除2,原理是乘法的豎式算法,// 101//x 010//------- 豎式算法適用于任何進制的加減法和乘法運算// 000//+101//-------// 1010//----------------------------------------------------------------------------int x = 7;List<Byte> bits = new List<Byte>(4);while (x != 0){var left = x - ((x >> 1) << 1);//<=> x - x/2*2bits.Add((byte)left);x = x >> 1;}}#endregion#region IEnumerableAndLinQclass Product{public int cateId;public string name;}class Category{public int id;public string name;}public static void TestIEnumerableAndLinq(){Category[] cates = new Category[]{new Category{id = 1, name = "水果"},new Category{id = 2, name = "飲料"},new Category{id = 3, name = "糕點"},};Product[] products = new Product[]{new Product{cateId=1, name = "apple"},new Product{cateId=1, name = "banana"},new Product{cateId=1, name = "pear/梨"},new Product{cateId=1, name = "grape/葡萄"},new Product{cateId=1, name = "pineapple/菠蘿"},new Product{cateId=1, name = "watermelon/西瓜"},new Product{cateId=1, name = "lemon/檸檬"},new Product{cateId=1, name = "mango/芒果"},new Product{cateId=1, name = "strawberry/草莓"},new Product{cateId=2, name = "bear/啤酒"},new Product{cateId=2, name = "wine"},new Product{cateId=3, name = "cake"},new Product{cateId=3, name = "basicuit/餅干"},};var rets = cates.Where((x) => { return x.id > 1 && x.id < 5; });var iter = rets.GetEnumerator();while (iter.MoveNext()){//WriteLine(iter.Current); }var set = from c in cates//這里只能寫一個條件,就是equals,用來關聯兩個表//并且 c相關的條件只能寫在equals左邊,p相關條件只能寫equals右邊join p in products on c.id equals p.cateId//這里存放的是 products中的元素合集,而不是cates中的元素合集//如果 from p in products join c in cates on c.id equals p.id into xgroups//則xgroups中放的是cates中的元素集合//這里是說將products中cateId等于c.id的所有元素放入一個組xgroups中 into xgroupsorderby c.id descending //對set中的結果進行降序排列//where m > 4 && m < 10 //這里就可以寫多個條件了//from in 相當于外層循環,join in 相當于內層循環//select在雙層循環體中,每執行一次循環,【如果符合條件】,則執行一次結果選擇//雙層循環完成后,最終將很多條選擇提交給set//【注意,如果不符合條件 select不會執行】select new { cate = c.name, grp = xgroups }; //可以生成一個新的對象foreach (var p in set){WriteLine("分組:" + p.cate);foreach (var g in p.grp){WriteLine(g.cateId + "," + g.name);}}}#endregion#region 類和繼承class CTestX{public virtual void OnUpdate(){Console.WriteLine("base-on-update");}public virtual void OnUpdate2(){Console.WriteLine("base-on-update2");}public void Update(){this.OnUpdate(); //注釋1,如果子類有overide則調用子類的,否則調用自己的 }public CTestX(){}protected CTestX(float fx){WriteLine("CTestX");}~CTestX(){WriteLine("~Ctestx");}public float fx;string name;}//子類不能訪問基類任何私有的東西,包括方法,字段,屬性,但它們都被繼承了,屬于子類,從實例內存可證//方法包括構造函數,即當基類是私有構造函數時,子類無法在初始化列表中調用base()來初始化class CTestChildX : CTestX{CTestX otestx;public CTestChildX() : base(1)//當基類為私有構造時,這里base無法調用{//當基類沒有無參構造函數時,必須在初始化列表中初始化所有成員對象,如otestxWriteLine("CTestChildX");}//注意overide與virtual的區別://1,overide : 表明【函數是對基類的重寫】 且 【本身是虛函數可被子類重寫】//【函數會與基類、子類發生虛函數機制】//2,virtual : 僅表明函數是個虛函數,不會與基類發生虛函數機制//如果子類overide了該函數,則會與子類發生虛函數機制//3,多級繼承中只要有一級沒override,虛函數機制就會打斷在此層級,見//override在編譯層的機制是重寫虛函數表中的函數地址//即將繼承而來的虛函數表中的虛函數地址替換成本類的虛函數地址public static void TestDerive(){// CTestX ox = new CTestChildX();// ox.OnUpdate(); //base-on-update,無虛函數機制發生// ox.OnUpdate2(); //child-on-update2,虛函數機制發生// ox = new CTestY();// ox.OnUpdate(); //base-on-update,無虛函數機制發生CTestChildX ocx = new CTestZ();ocx.OnUpdate(); //grand-child-on-update }public override void OnUpdate(){Console.WriteLine("child-on-update");}public override void OnUpdate2(){Console.WriteLine("child-on-update2");}~CTestChildX() //不支持virtual {WriteLine("~CTestChildX");}}class CTestY : CTestChildX{public override void OnUpdate(){Console.WriteLine("grand-child-on-update");}}class CTestZ : CTestY{//因為這里的Update不是虛函數,因此public void OnUpdate(){Console.WriteLine("grand-grand-child-on-update");}}struct CTX{void Test() {//不支持C++的const語法 }}//1,不能繼承結構,可以實現接口,//2,不能有虛函數struct CCTX //: CTX {public void Test(){}}#endregion#region 字符串格式化static void TestStrFormat(){var str = Console.ReadLine();while (str != "exit"){int ix;Int32.TryParse(str, out ix); //ix = 120var f1 = string.Format("{0 :d5}", ix); //"00120"var f2 = string.Format("{0,-10:d5}", ix);//"00120 "var f3 = string.Format("{0:x}", ix); //16進制輸出到字符串var f4 = string.Format("{0:0.000}", ix);//浮點數 120.000Console.WriteLine("-----------begin-------------");Console.WriteLine(f1);Console.WriteLine(f2);Console.WriteLine(f3);Console.WriteLine(f4);Console.WriteLine("------------end-------------");str = Console.ReadLine();}}#endregion#endregion#region 2018.7.25#region 引用返回值(不是右值引用)static int[] _bookNum = new int[] { 1, 2, 3, 4, 5, 6 };static ref int GetBookNumber(int i){int x = 10;return ref _bookNum[i];}static void TestRefReturn(){ref int rfn = ref GetBookNumber(1);rfn = 10101; //_bookNum[1]變成了 10101int vn = GetBookNumber(2);vn = 202; //_bookNum[2]未變,仍為3ref int x = ref vn;}#endregion#region 索引器class mylist<T>{const int defaultCap = 4;T[] items;int count;int cap = defaultCap;public mylist(int cap = defaultCap){if (cap != defaultCap)this.cap = cap;items = new T[cap];}public T this[int idx] {set {items[idx] = value;}get {return items[idx];}}}enum Color{red,green,blue,yellow,cyan,purple,black,white,}static void TestIndexer(Color clr = Color.black){mylist<string> lst = new mylist<string>();lst[1] = "hello";}#endregion#region 部分類//部分類的作用是可以把一個龐大的類拆分到多個文件,每個文件實現一部分//而不是實現像C++那樣將聲明與實現分開//若要實現聲明(接口)與實現分開,應該使用抽象類或接口partial class CPartclass{public void ShowName() {WriteLine("show name");}}partial class CPartclass{public void ShowAge(){WriteLine("show age");}}static void TestPartclass(){CPartclass opc = new CPartclass();opc.ShowName();opc.ShowAge();}#endregion#region 動態分配對象數組C#與C++的區別struct xobject {public float fx, fy, fz; //全是public的 }static void TestDynamicAllocInCSharpCpp(){//1,對于引用類型數組,需要兩步才能完成,因為數組中存放的是對象的引用//1.1 c#中xobject[] arr = new xobject[2];//這時候,只是分配了一個引用數組,arr[0],arr[1]均為nullfor (int i = 0; i < 2 ; i++){arr[i] = new xobject(); //為數組中每個引用申請對象 }//1.2 c++中//xobject** pp = new xobject*[2];//pp[0] = new xobject();//pp[1] = new xobject();//2 對于值類型數組,則只需一步,因為數組中放的就是值,這在C#與CPP中都一樣//2.1 C#中int[] iarr = new int[2];var a0 = iarr[0]; //0var a1 = iarr[1]; //0 xobject[] varr = new xobject[3];varr[0].fx = 0.1f;varr[1].fy = 2.5f;varr[2].fz = 12;//2.2,在C++中//xobject* pobjs = new xobject[2]; //每個數組元素都是一個值類型對象//pobjs[0].fx = 20; }#endregion#region Object?語法static void TestobjAsk(){object obj = "hello";WriteLine(obj?.ToString());//如果obj不為null則調用tostring }#endregion#region C#默認字符編碼及系統默認編碼//默認編碼為unicode,字符串本身的編碼并不重要,字節讀寫時指定的編碼才重要,如下面的BinaryWriter//Encoding.Default是當前系統的默認編碼,并不是c#字符串的默認編碼//Encoding.Default規則:漢字2字節,其它1字節static void TestDefaultStrEncoding(){string str = "hdd好";using (var ms = new MemoryStream()){using (var br = new BinaryWriter(ms, Encoding.Default)){br.Write(str);var len = ms.Length-1;WriteLine(len);}}}#endregion#region 屬性attribute和反射class ReflectableClass{public float fx;public string str;//static const int x = 20; //這在C++中是可以的public void Printstr(string str, int idx){WriteLine(str + ":" + idx);}}static void TestReflect(){ReflectableClass ox = new ReflectableClass();Type t = typeof(ReflectableClass);//Type.GetType("ConsoleApplication1.Program.ReflectableClass");//ox.GetType();var tname = t.GetField("name");var tfx = t.GetField("fx");var func = t.GetMethod("Printstr", new Type[] {typeof(string),typeof(int) });func.Invoke(ox, new object[] { "helloworld", 1 });Type Ts = Type.GetType("System.String");var fs = Ts.GetMethod("Substring", new Type[] { typeof(int), typeof(int) });var subs = fs.Invoke("hello world", new object[] { 1, 5 });WriteLine(subs);}static void TestAttribute(){}#endregion#endregion#region 2018.7.30#region 擴展方法測試static void TestExtMethod(){ExtTargetCls oet = new ExtTargetCls();oet.methodExt(100);WriteLine(oet.sum);}#endregion#region 元組:同時傳遞多個不同類型參數//作用時,可以很方便的,高效的返回一組不同類型的值或對象//因為是泛型,所以高效//但是它最多只有8個參數,也就是說不能當作ArrayObject的替代品static void TestTuple(){Tuple<int, float> tupleFunx(){return new Tuple<int, float>(1, 2);}var tp = tupleFunx();WriteLine(tp.Item1);WriteLine(tp.Item2);}#endregion#region 數組排序:實現IComparable和傳遞排序函數//注意,List排序也是這樣的,因為它本身就是一個數組class ComparableObj<T> : IComparable{public T elem;public ComparableObj(T fx){elem = fx;}public int CompareTo(object obj){var objc = (dynamic)(ComparableObj<T>)obj;if (elem == objc.elem)return 0;else if (elem < objc.elem)return -1;return 1;}}static void TestCompareableobj(){var rand = new Random();ComparableObj<float>[] arrf = new ComparableObj<float>[10];for (var i = 0; i < 10; ++i){arrf[i] = new ComparableObj<float>(rand.Next(1, 100));Write(arrf[i].elem + " ");}WriteLine();//方式一,實現了IComparable,用它來排序,升序 Array.Sort(arrf);foreach (var a in arrf){Write(a.elem + " ");}WriteLine();//方式二,傳遞一個排序函數,使用它來排序,降序Array.Sort(arrf, (a, b) =>{if (a.elem == b.elem)return 0;else if (a.elem < b.elem)return 1;return -1;});foreach (var a in arrf){Write(a.elem + " ");}WriteLine();}#endregion#region 只讀集合void TestReadonlySet(){var lst = new List<int>();var rdlst = lst.AsReadOnly(); //生成一個包裝類,引用原來的lst,因此是高效的//rdlst[0] = 2; //error, read onlyvar llst = new LinkedList<int>();//這個才是鏈表,而list就像是c++的vector }#endregion#endregion#region 2018.7.31#region JSONvoid TestJson(){}#endregion#region CPP與CS間數據傳遞轉換#endregion#region 線程static void TestThread(){//Thread.Yield();Thread t1 = new Thread(() =>{int i = 0;while (i++ < 25){Thread.Sleep(300);WriteLine("T1>> " + i);}});Thread t2 = new Thread(() =>{//t1先執行(<=1000毫秒),t2等待t1.Join(1000);//t1,t2同時執行,若上一步t1已完成則不執行int i = 0;while (i++ < 10){Thread.Sleep(300);WriteLine("T2>> " + i);}//若t1還活著,繼續執行//t2是前臺線程,main函數會等待t2的結束 t1.Join();});t1.Start();t2.Start();t1.IsBackground = true;t2.IsBackground = true;//t1.IsBackground = true;//t2.Join();Thread.Sleep(2000);WriteLine("main-thread-end");}#endregion#region 線程池void TestThreadPool(){}#endregion#region 任務static void TestTask(){WriteLine("TestTask: " + Thread.CurrentThread.ManagedThreadId);//任務開啟方式一,實例實現var task = new Task(() =>{WriteLine("task: " + Task.CurrentId + "," + Thread.CurrentThread.ManagedThreadId);});task.Start();task.Wait(); //等待方式一Task.WaitAny(task); //等待方式二//任務開啟方式二,靜態方法實現var t1 = Task<string>.Run(delegate //Task<string>中的string表示返回值類型,也可不寫,由模板自動推導 {WriteLine("task1: " + Task.CurrentId + "," + Thread.CurrentThread.ManagedThreadId);Thread.Sleep(2000);return "suceed"; //返回值類型,對應Task<string>中的string,如果類型寫錯也沒關系 });t1.Wait(); //等待任務完成,因為是在主線程中調用的,因此是讓主線程等待任務完成,不寫的話主線程直接結束了WriteLine("線程1執行結果:" + t1.Result); //suceed }#endregion#region 程序集#endregion#region 多線程調試#endregion#region 委托綜合使用小例子static void delegateTestx0 (){void ifunc(int x, Func<int, int> dx){WriteLine(dx(2));}var lst = new List<int>() { 1, 2, 3 };foreach (var v in lst){ifunc(1, delegate (int x) {//像lua的回調函數那樣使用return v; //閉包中的v });ifunc(1, (x) => { return v; });}}#endregion#region 異步 async awaitpublic static async void AsyncFunc(){WriteLine(Thread.CurrentThread.ManagedThreadId); //主線程var task = Task.Run(() =>{for(int i= 0; i<10; ++i){WriteLine(Thread.CurrentThread.ManagedThreadId + ":task>>" + i); //線程1Thread.Sleep(100);}});var task1 = Task.Run(() =>{for (int i = 0; i < 10; ++i){WriteLine(Thread.CurrentThread.ManagedThreadId + ":task1>>" + i);//線程2Thread.Sleep(100);}});await task; //等待線程1完成await task1;//等待線程2完成WriteLine("task and task1 finished");var task2 = Task.Run(() =>{for (int i = 0; i < 10; ++i){WriteLine(Thread.CurrentThread.ManagedThreadId + ":task2>>" + i);//線程3Thread.Sleep(100);}});await task2;//等待線程3完成Task.WaitAll(task, task1, task2); //無效,因為代碼執行到這里時主線程已結束WriteLine("---------------------------------------------------");}public static void AsyncFunc2(){WriteLine(Thread.CurrentThread.ManagedThreadId); //主線程var task = Task.Run(() =>{for (int i = 0; i < 10; ++i){WriteLine(Thread.CurrentThread.ManagedThreadId + ":task>>" + i); //線程1Thread.Sleep(100);}});var task1 = Task.Run(() =>{for (int i = 0; i < 10; ++i){WriteLine(Thread.CurrentThread.ManagedThreadId + ":task1>>" + i);//線程2Thread.Sleep(100);}});task.Wait();//等待線程1完成task1.Wait();//等待線程2完成WriteLine("task and task1 finished");var task2 = Task.Run(() =>{for (int i = 0; i < 10; ++i){WriteLine(Thread.CurrentThread.ManagedThreadId + ":task2>>" + i);//線程3Thread.Sleep(100);}});task2.Wait();//等待線程3完成WriteLine("---------------------------------------------------");}//-----------------------------------------------------------------------//異步方式實現多個任務(線程)間的并發執行與順序執行//一個任務就是一個線程//await task 與task.wait的區別://task.wait會阻住當前線程,直到task執行完成,而await不會,它只表明了當前在任務會在task之后執行//-----------------------------------------------------------------------//方式一,采用 async-await方式實現//這種方式寫起來較優雅,但較抽象,且不知道所有任務的結束點,Task.waitAll對此無效static void TestAsyncAwait(){WriteLine(Thread.CurrentThread.ManagedThreadId); //主線程 AsyncFunc();WriteLine("after asyncfunc");//必須這樣等待任務結束,因為AsyncFunc中的Task.WaitAll無效//或者將每個任務都設置為前臺線程Thread.Sleep(3000); }//方式一,采用不使用 async-await關鍵詞,直接使用Task的基本功能來實現//這種方式更直觀,易于理解,且利于控制static void TestAsyncWait(){WriteLine(Thread.CurrentThread.ManagedThreadId); //主線程var task = Task.Run((Action)AsyncFunc2);WriteLine("after asyncfunc");task.Wait();}#endregion#region 正則表達式#region 貪婪匹配和最少匹配#endregion #region 分組 #endregion#endregion#region 正則在字符串中的使用static void TestRegexInStr(){var st = "hello;world;a";var mt = Regex.Match(st, ";world;");var ret = mt.Result(".");//???// string pattern = "--(.+?)--"; // string replacement = "($1)"; // string input = "He said--decisively--that the time--whatever time it was--had come."; // foreach (Match match in Regex.Matches(input, pattern)) // { // string result = match.Result(replacement); // Console.WriteLine(result); // } }#endregion#endregion#region 2018.8.1#region 異步調用Invokedelegate void MyTakeAwhileDelegate(int x, int time);static MyTakeAwhileDelegate a = invokefunc;static void invokefunc(int x, int time){WriteLine("begin invoke: " + Thread.CurrentThread.ManagedThreadId);//var str = Console.ReadLine();//WriteLine(">>" + str); Thread.Sleep(time);}static void TestInvoke(){// var iar = a.BeginInvoke(delegate(IAsyncResult ar) {// WriteLine("complete: " + ar.IsCompleted);// WriteLine("end invoke: " + Thread.CurrentThread.ManagedThreadId);// TestInvoke();// // }, null);//【線程的順序執行模式】//多個線程對同一函數進行順序訪問,不需要考慮線程同步問題,也不需要waitone等操作//不管系統會使用多少個線程來處理工作,但同時只有一個在執行,EndInvoke保證了這一點//這種模式在網游客戶端中很有用,客戶端只需要2個線程:一個主線程用于處理游戲邏輯與顯示畫面//另一個線程則用于與后端進行網絡通訊,這個線程就只需要使用【線程的順序執行模式】//來循環處理網絡消息:讀取網絡消息,阻塞等待讀取完成,然后再讀取網絡消息,阻塞等待讀取完成...while (true){//注意這里的參數與委托對應,而且多了兩個:callback, obj是系統加的var ar = a.BeginInvoke(1, 1000, null, null);a.EndInvoke(ar); //阻塞,只到線程執行完線程函數 }//a.EndInvoke(iar);//iar.AsyncWaitHandle.WaitOne(); }#endregion#region 初始化器class CInitclass{public CInitclass() { }public CInitclass(string name, int age){this.name = name; this.age = age;}public string name;public int age;}static void TestInitial(){var oc = new CInitclass { name = "jim", age = 14 };var oc1 = new CInitclass() { name = "jim", age = 14 };var oc2 = new CInitclass("tim", 13) { name = "jim", age = 14 };var oc3 = new { name = "jim", age = 14, sex = 1 }; //匿名對象int[] arr = { 1, 2, 3 };int[] arr2 = new int[] { 1, 2, 3 };List<int> lst = new List<int> { 1, 2, 3 };List<int> lst1 = new List<int>(10) { 1, 2, 3 }; //capacity = 10lst1.Capacity = 5;WriteLine(lst1.Capacity);lst1.ForEach((i) => WriteLine(i));var dict = new Dictionary<int, string> { { 1, "a" }, { 2, "b" }, { 3, "c" } };var dict1 = new Dictionary<int, string>() { { 1, "a" }, { 2, "b" }, { 3, "c" } };}#endregion#region 協變和逆變//協變發生在數組,模板,委托上,//父子類之間的轉換不是協變,不是逆變//轉變的前提是元素類型有父子關系,如 class A{}; class B : A{}; B b; A a;//若子群可以轉為父群,則稱為協變,如 A[] a = new B[10]//協變必須是在引用類型之間,值與引用類型之間是不能協變的,如 object[]和 int[]//雖然 object是int的父類,但 int 是值類型//再如 object[] strs = new string[10]是可以的,因為 object就string的父類且二者都是引用類型//======================================================================//總結:協變和逆變只是父子對象間轉換規則在模板,委托,數組上的表現//本質上還是子對象轉父對象,沒有父對象轉子對象的現象存在//模板類中的協變與逆變轉換過程較為抽象,難時一眼看出,解析方法是:用實際生成的對象去調用,在調用過程中分析//如下面的二例:【泛型委托中的協變逆變】和【泛型接口中的協變逆變】#region 普通協變逆變class tshape<T> { }class tcircle<T> : tshape<T> { }static void xiebianx(CTestX[] array){array = new CTestChildX[10];}static void TestXiebianNibian(){object[] ocs = new CNormclass[10];object[] strs = new string[10];//協變的一個陷阱,編譯時正常,運行時拋出異常: 類型不匹配strs[0] = 10;//泛型類本身的協變(有父子關系,泛型參數相同)tshape<int>[] tsps = new tshape<int>[10];tshape<CNormclass>[] tcs = new tcircle<CNormclass>[10];//通過函數參數測試普通類的轉變CTestX[] ox = new CTestX[10];xiebianx(ox);}#endregion#region 委托中的協變逆變class XIEBIAN{delegate CTestX[] ArrDelegate();CTestChildX[] func001(){return new CTestChildX[10];}delegate CTestX JustDelegate();CTestChildX func002(){return new CTestChildX();}void TEst(){ArrDelegate ad = func001;JustDelegate dd = func002;}}#endregion#region 泛型委托中的協變逆變delegate void FuncPtrin<in T>(T ox);//這里的in僅用來限制T類型,說明T只可用于輸入參數,而不能用于輸出。in與協變逆變無關??梢匀コ?/span>void testfuncptr1(CTestX ox){}delegate T FuncPtrout<out T>();//out限制T只能用于輸出參數,即返回值。與協變逆變無關。可去除 CTestX testfuncptr2(){return new CTestChildX();}void testfuncptr(){//泛型委托的協變比較抽象,其實,從它的【調用原理】來思考就很容易了FuncPtrin<CTestChildX> p1 = testfuncptr1;FuncPtrin<CTestX> p2 = testfuncptr1;//【調用原理】://1,p1的實參必須是T類型//2,p1的實參必須能傳入它指向的函數中p1(new CTestChildX());p2(new CTestChildX());p2(new CTestX());FuncPtrout<CTestX> p3 = testfuncptr2;CTestX otx = p3();//-----------------------------------------------------------------------//其實這里不存在什么所謂的逆變,只有一種規則:子對象可以轉為父對象//只要讓參數接收者和返回值接收者都是父對象,就可以了//----------------------------------------------------------------------- }#endregion#region 泛型接口中的協變逆變class CAnimal {}class CDog : CAnimal{}interface ISpeak<in T, out T2>//這里的in和out就是協變逆變的關鍵了,沒有它們編譯器不知道如何進行父子關系轉換 {T2 PrintInfo(T o);float fx { set; get; }}class Speaker<T, T2> : ISpeak<T, T2>where T2 : new() //必須有公有無參構造函數(或默認構造函數) {public float fx { set; get; }public T2 PrintInfo(T o){return new T2();}}void Test003(){ISpeak<CDog, CAnimal> speaker = new Speaker<CAnimal, CDog>();speaker.PrintInfo(new CDog());}#endregion#endregion#region 2018.8.2#region 相等比較static void TestVarEquals(){//--------------------------------------------------------------//C#中字符串都是常量,但在底層實現上還是C++的方式,分為常量字符串與變量字符串//1,以數組形式給出的字符串是變量字符串//2,以字符串形式給出的是常量字符串//每個變量字符串都有不同的地址,而一個常量字符串只有一個地址,它是全局的//如下sa, sb指向兩個地址不同而內容相同的字符串,sa1,sb1都指向同一個常量字符串"hello"string sa = new string(new char[] { 'h', 'e', 'l', 'l', 'o' }); //變量字符串string sb = new string(new char[] { 'h', 'e', 'l', 'l', 'o' });//變量字符串string sa1 = "hello";//常量字符串string sb1 = "hello";//常量字符串WriteLine(sa.GetHashCode() + "," + sb.GetHashCode());WriteLine(sa.Equals(sb));//true,調用string.equals(string)WriteLine(sa == sb);//true,string的operator ==object oa = sa;object ob = sb;object oa1 = sa1;object ob1 = sb1;WriteLine(oa.Equals(ob));//true, 多態調用,實際調用的是string.Equals(object)WriteLine(oa1.Equals(ob1));//true, 多態調用,實際調用的是string.Equals(object)//運行時,打印sa,sb, sa1, sb1的地址,可以看到sa,sb中存放的地址不同,sa1,sb1中存放的地址相同// &sa// 0x000000000028ecb0// * &sa: 0x0000000002472ed8// & sb// 0x000000000028eca8// * &sb: 0x0000000002472f70// & sa1// 0x000000000028eca0// * &sa1: 0x0000000002472dc0// & sb1// 0x000000000028ec98// * &sb1: 0x0000000002472dc0WriteLine("ref equal : " + ReferenceEquals(sa, sb));WriteLine("ref equal : " + ReferenceEquals(sa1, sb1));WriteLine("oa == ob: " + (oa == ob)); //false,oa,ob中存放的地址不同WriteLine("oa1==ob1: " + (oa1 == ob1)); //true,oa1,ob1中存放的地址相同,都是常量字符串hello的地址 object oc = new object();object od = new object();WriteLine(oc.Equals(od)); //false, object.equals(object)WriteLine(oc == od);//false//如果沒有實現重寫,對于引用類型,那么原始的object.equals()與 ==沒有任何區別,二者總能得到一樣的結果//因為引用類型其實是一個指針,==比較的是指針的值,也就是地址,equals比較的也是地址。//string類重寫了==和equals,實現了字符串內容的比較,而非地址的比較。object o1 = new CNormclass();object o2 = new CNormclass();WriteLine(o1.Equals(o2)); //false, 多態調用, CDefOveride.Equals(object)int ia = 12;short isa = 12;WriteLine(ia.Equals(isa)); // true, short可以轉為int,故多態調用Int32.Equals(Int32 obj)WriteLine(isa.Equals(ia)); // false, int不能直接轉為short,故多態調用Int16.Equals(object obj) }#endregion#endregion#region 2018.8.3#region 線程同步#region 同步事件和等待句柄//https://docs.microsoft.com/zh-cn/dotnet/csharp/programming-guide/concepts/threading/thread-synchronizationstatic void TestWaitHandle(){//自動重置事件//一次只能激活一個線程,因為一旦激活后信號被自動置為了falsevar autoEvent = new AutoResetEvent(false);void tfunc(object o){WriteLine("worker thread " + (int)o + " started, now waiting on some event ... ");autoEvent.WaitOne();WriteLine("worker thread " + (int)o + " reactivated, now exiting...");}var threads = new Stack<Thread>();WriteLine("輸入創建 的線程數");var num = 1;while (!(int.TryParse(ReadLine(), out num))){}for(int i=0; i < num; ++i){var t = new Thread(tfunc);t.Start(i);threads.Push(t);Thread.Sleep(20);}Thread.Sleep(1000);while(threads.Count > 0){ReadKey();autoEvent.Set(); //發出信號,設置信號為true,一旦有線程被激活后,信息就被設置為了false threads.Pop();}}#endregion#region 一個線程終止另一個線程及信息傳遞異常捕獲class CThreadAbortInfo{public string info;public CThreadAbortInfo(string s){info = s;}}static void TestThreadAbort(){var t1 = new Thread(() =>{WriteLine("t1 started");try{int i = 0;while (true){Write(".");Thread.Sleep(200);i = i / 0;}}catch (DivideByZeroException e)//如果不處理,則系統會自己處理 {//throw; //讓程序引發異常,如果不寫,則程序正常運行,因為異常被丟棄了 }catch (ThreadAbortException ex)//如果不處理,程序正常運行 {var info = ex.ExceptionState as CThreadAbortInfo;if (info != null){WriteLine(info.info);}}});t1.Start();var t2 = new Thread(() =>{Thread.Sleep(1000);//調用這個函數,會拋出異常,但若不去捕獲,程序就什么都不會發生//拋出異常與顯示異常是不同的t1.Abort(new CThreadAbortInfo("t1 is terminated by thread t2"));});t2.Start();}#endregion#endregion#region as和引用類型轉換本質void Refcasttype(){//注意,不論是as轉換還是強制轉換都是在指針轉換,而不是對象轉換,遵守C++的規則:子類可以轉父類//C#中,父類也可以轉子類,因為它們都是指針,但若實際類型不符合則結果為空var o = new CNormclass();var t = o as IDisposable;var ot = new CTestX();var ot2 = new CTestChildX();WriteLine("as1: " + ((CTestChildX)ot));WriteLine("as1: " + (ot as CTestChildX));WriteLine("as3: " + (ot2 as CTestX));WriteLine("as4: " + ((CTestChildX)ot2));using (ot as IDisposable)//判斷如果它實現了該接口 {}}#endregion#region 多播委托delegate void MDX();static void TestMultiDelegate(){void func1(){WriteLine("func1");}void func2(){WriteLine("func2");}void func3(){WriteLine("func3");}MDX md = func1; //【!】第一步不能寫 +=,因為它還沒有初始值md += func3;md += func2;md(); //func1 func3 func2 執行順序與添加順序相同md -= func1;md(); //func3 func2//md -= (func2 + func3); //wrongmd = func1; //ok,事件不允許這樣 md();md -= func1; //編譯運行都OK,調用出錯md -= func2; //編譯運行都OK,調用出錯md();//調用異常 }#endregion#region UDP通信static void TestUDp(){var ipenda = new IPEndPoint(IPAddress.Parse("127.0.0.1"), 11000);var ipendb = new IPEndPoint(IPAddress.Parse("127.0.0.1"), 12000);void StartUdpClientA(){UdpClient udp = new UdpClient(ipenda);//udp.Connect(ipendb);while (true){var recvBytes = udp.Receive(ref ipendb);var bytes = Encoding.ASCII.GetBytes("信息已收到[" + recvBytes.Length + "],請繼續發送");Thread.Sleep(1000);udp.Send(bytes, bytes.Length, ipendb);}}void StartUdpClientB(){UdpClient udp = new UdpClient(ipendb);//udp.Connect(ipend);while (true){WriteLine("請輸入發信息:");var str = ReadLine();var bytes = Encoding.ASCII.GetBytes(str);udp.Send(bytes, bytes.Length, ipenda);WriteLine("信息已發送等待回復:");var recvBytes = udp.Receive(ref ipenda);WriteLine(">>收到回復,字節數:" + recvBytes.Length);}}var t1 = new Thread(StartUdpClientA);var t2 = new Thread(StartUdpClientB);t1.Start();t2.Start();}#region TCP通信#endregion#endregion#region 可空類型void TestNullabletype(){//可空類型是一個泛型結構體Nullable<int> ix0 = null;//等同于下式int? ix = null; //可空類型object oa = 5;int iy = ix ?? 7; //7object ob = oa ?? 10; //5 WriteLine(iy);WriteLine(ob);}#endregion#endregion#region 2018.8.4#region 抽象類與接口對比interface ixinterface//不能加sealed {//1, 接口中不能寫public,因為默認為public,C#不會存在可有可無的東西//2,接口可以有抽象int this[int x] { set;get; } //3,接口中不可以寫實例化字段和屬性//4,可以有事件 }abstract class AbstractClass//不能加sealed {//int this[int x] { set; get; }int ix { set; get; }public abstract int iy { set; get; }void Func() { }int this[int x] {//可以定義索引器,但必須實現set { }}}class Dabclass : AbstractClass{public override int iy { get => throw new NotImplementedException(); set => throw new NotImplementedException(); }}#endregion#endregion#region C#的析構函數不同于C++class myTemp<T>{public myTemp(){}/*private virtual */~myTemp(){//析構函數不能帶任何限制聲明,如public, protected, private, }}class Tehua : myTemp<string>{}#endregion #region 2018.8.14static void testIntLimit(){var le = -2147483648 < 2147483648;int ix = -2147483648;WriteLine(ix - 1); //0x80000000 + 0xffffffff = 0x7fffffff } #endregion#endregion// ctrl + w, t 可以察看所有待做任務static void Main(string[] args){//TestVarEquals();//TestUDp();//TestWaitHandle();//TestThreadAbort();//TestMultiDelegate();//TestVarEquals();//TestInitial();//TestInvoke();//Thread.Sleep(30000);//TestXiebianNibian();//TestAsyncWait();//TestTask();//TestThread();//TestRegexInStr();//TestCompareableobj();//TestExtMethod();//TestReflect();//TestDefaultStrEncoding();//TestDynamicAllocInCSharpCpp();//TestPartclass();//TestRefReturn();//TestOperatorOverload();// CTestChildX.TestDerive();//TestFloat();//var arr = returnArray(); }}#region 擴展方法sealed class ExtTargetCls{public float sum = 10;}//擴展方法必須在頂級靜態類中定義,不能是內部類//能不能通過擴展方法來修改類庫以達到不法目的? 不能,因為擴展方法只能修改類的公有成員static class ExtentMethod{public static void methodExt(this ExtTargetCls target, float add){target.sum += add;}}#endregion}?
posted on 2018-08-14 11:25 時空觀察者9號 閱讀(...) 評論(...) 編輯 收藏
總結
以上是生活随笔為你收集整理的2018.8.14-C#复习笔记总的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 2018.8.14-C++复习笔记总
- 下一篇: 【转】【Unity+Lua】实测如何性能