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#复习笔记总相关推荐

  1. 2018.8.14-C++复习笔记总

    2018.8.14-C++复习笔记总 // CPPTEST.cpp : 定义控制台应用程序的入口点. // #include "stdafx.h" #include<iost ...

  2. 2018.8.5 复习笔记

    2018.8.5 复习笔记 1,"a" + "b" + 3 strcat double d = 3 object obj = d int i = (int)ob ...

  3. 2018.8.14笔记

    2018.8.14笔记 setsiblingindex(idx)设置兄弟结点先后顺序时,若idx处已有结点X,则结点X及其后的所有节点后移 gc alloc,就是申请堆内存,堆内存申请无处不在,不可能 ...

  4. 复习笔记2018.8.3

    复习笔记2018.8.3 1,"a" + "b" + 3 strcat double d = 3 object obj = d int i = (int)obj ...

  5. 《微型计算机原理与接口技术》期末总复习 —— 一篇匆匆忙忙的复习笔记

    这篇复习笔记是针对<微型计算机原理与接口技术>后面几章的 前面的汇编复习内容在 "零.学习笔记总目录" 的 "汇编考前复习" 中 ✅ 这篇笔记中可能 ...

  6. 计算机网络复习笔记——考试版

    计算机网络复习笔记 文章目录 计算机网络复习笔记 第一章 计算机网络和因特网 1.1 什么是因特网--因特网的具体构成 1.2 网络边缘 1.3 网络核心 1.4 分组交换网络中的时延.丢包和吞吐量 ...

  7. 【期末复习笔记】知识产权法——著作权、专利法、商标权

    [期末复习笔记]知识产权法 著作权 著作权法不予以保护的客体 著作权的归属 著作权的内容 著作人身权 著作财产权 著作权的取得方式:自动取得 著作权的保护期限: 邻接权 表演者权 表演者义务 表演者权 ...

  8. 计算机网路原理复习笔记

    计算机网路原理复习笔记 未看: 前两章 第四章路由聚合 第四章最长前缀匹配 SDN 3. 数据链路层 3.1 基本概念和功能概述 3.1.1 链路:是一条无源的点到点的物理线路段,中间没 有任何其他的 ...

  9. 大学物理:第10章 静电场 复习笔记

    大学物理:第10章 静电场 复习笔记 大学物理 大学物理:第10章 静电场 复习笔记 一级目录 二级目录 三级目录 一.电荷与库仑定律 1.电荷 2.库仑定律 3.静电力的叠加原理 二.电场与电场强度 ...

最新文章

  1. Oozie 配合 sqoop hive 实现数据分析输出到 mysql
  2. 【面试题】struts2的工作流程
  3. Newbe.Claptrap 框架入门,第二步 —— 创建项目
  4. Cacti 监控平台搭建
  5. github 搜索_github 项目搜索技巧让你更高效精准地搜索项目
  6. thrift 学习 了解
  7. android u盘加载_如何获取Android系统挂载U盘的路径
  8. c#Struts框架理念和自制Struts框架下 复杂版(2009-06-10)
  9. SMC 如何下载三维及二维图
  10. 一句powershell调用mimikatz抓密码
  11. 从零开始搭建ABP框架(Asp .Net Boilerplate)+Oracle(11 g)
  12. sobol灵敏度分析matlab_灵敏度分析_使用MATLAB编写.doc
  13. 像距为什么要大于焦距?
  14. 牛津词典 2018 年度词汇 ——「有毒」! 1
  15. 始料未及-- 元宇宙传来好消息,全球轰动
  16. 游戏服务器会遭到什么攻击,被攻击了怎么防御
  17. php支付宝红包接口,支付宝支付接口(即时到账交易接口)
  18. mac系统python读取文件路径_python读取文件常见问题(Mac版)
  19. 学习vue加OpenLayers(3)动画 GIF
  20. 当代研究生英语读写教程的前5章译文

热门文章

  1. Node-RED安装图形化节点dashboard实现订阅mqtt主题并在仪表盘中显示温度
  2. 使用MAT做jvm的GC Roots溯源
  3. weblogic从入门到起飞(wlst)(四)
  4. 谈谈产品开发团队的配置管理规则
  5. Flutter+百度人工智能实现测验值app
  6. java之整数的分解可以理解为倒序输出
  7. nanopi磁盘烧写
  8. 十周年“设计大佬”首谈行业变革:数据驱动超过 10% 的业绩增长
  9. 神策数据全面支持出海客户合规 GDPR!
  10. 多部门数据分析需求,如何满足?