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与协变逆变无关。可以去除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++复习笔记总
2018.8.14-C++复习笔记总 // CPPTEST.cpp : 定义控制台应用程序的入口点. // #include "stdafx.h" #include<iost ...
- 2018.8.5 复习笔记
2018.8.5 复习笔记 1,"a" + "b" + 3 strcat double d = 3 object obj = d int i = (int)ob ...
- 2018.8.14笔记
2018.8.14笔记 setsiblingindex(idx)设置兄弟结点先后顺序时,若idx处已有结点X,则结点X及其后的所有节点后移 gc alloc,就是申请堆内存,堆内存申请无处不在,不可能 ...
- 复习笔记2018.8.3
复习笔记2018.8.3 1,"a" + "b" + 3 strcat double d = 3 object obj = d int i = (int)obj ...
- 《微型计算机原理与接口技术》期末总复习 —— 一篇匆匆忙忙的复习笔记
这篇复习笔记是针对<微型计算机原理与接口技术>后面几章的 前面的汇编复习内容在 "零.学习笔记总目录" 的 "汇编考前复习" 中 ✅ 这篇笔记中可能 ...
- 计算机网络复习笔记——考试版
计算机网络复习笔记 文章目录 计算机网络复习笔记 第一章 计算机网络和因特网 1.1 什么是因特网--因特网的具体构成 1.2 网络边缘 1.3 网络核心 1.4 分组交换网络中的时延.丢包和吞吐量 ...
- 【期末复习笔记】知识产权法——著作权、专利法、商标权
[期末复习笔记]知识产权法 著作权 著作权法不予以保护的客体 著作权的归属 著作权的内容 著作人身权 著作财产权 著作权的取得方式:自动取得 著作权的保护期限: 邻接权 表演者权 表演者义务 表演者权 ...
- 计算机网路原理复习笔记
计算机网路原理复习笔记 未看: 前两章 第四章路由聚合 第四章最长前缀匹配 SDN 3. 数据链路层 3.1 基本概念和功能概述 3.1.1 链路:是一条无源的点到点的物理线路段,中间没 有任何其他的 ...
- 大学物理:第10章 静电场 复习笔记
大学物理:第10章 静电场 复习笔记 大学物理 大学物理:第10章 静电场 复习笔记 一级目录 二级目录 三级目录 一.电荷与库仑定律 1.电荷 2.库仑定律 3.静电力的叠加原理 二.电场与电场强度 ...
最新文章
- Oozie 配合 sqoop hive 实现数据分析输出到 mysql
- 【面试题】struts2的工作流程
- Newbe.Claptrap 框架入门,第二步 —— 创建项目
- Cacti 监控平台搭建
- github 搜索_github 项目搜索技巧让你更高效精准地搜索项目
- thrift 学习 了解
- android u盘加载_如何获取Android系统挂载U盘的路径
- c#Struts框架理念和自制Struts框架下 复杂版(2009-06-10)
- SMC 如何下载三维及二维图
- 一句powershell调用mimikatz抓密码
- 从零开始搭建ABP框架(Asp .Net Boilerplate)+Oracle(11 g)
- sobol灵敏度分析matlab_灵敏度分析_使用MATLAB编写.doc
- 像距为什么要大于焦距?
- 牛津词典 2018 年度词汇 ——「有毒」! 1
- 始料未及-- 元宇宙传来好消息,全球轰动
- 游戏服务器会遭到什么攻击,被攻击了怎么防御
- php支付宝红包接口,支付宝支付接口(即时到账交易接口)
- mac系统python读取文件路径_python读取文件常见问题(Mac版)
- 学习vue加OpenLayers(3)动画 GIF
- 当代研究生英语读写教程的前5章译文