• 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); //1
    
                var 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('');
                string s3 = "hello/0/0dddddd".TrimStart('');//!!!!!!!!!!!!!!!!!!!!!!!!!!!!    
    
            }
    
            #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";
                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和的区别,如 s1="h0ello", s2 = "hello"
                //s2中的是字符串结尾符,除了C#不把它作为结束符外,其它语言都把它作为结束符,如U3D,LUA,C/C++等
                //而s1中的0仅是一个字符0而已,字符0的ASCII值是0X31=49,''的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 += '' + ",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,输出结果为:base
                var 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 template
            class 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);
                }
    
                //测试 A
                var t1 = 100000 * Test1(idict);
    
                //测试 B
                var 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; //error
            float fxs3 = sfxs; //right,可用静态字段初始化
            float fxs4 = TestStaticInit(); //right,调用静态函数初始化
            static int TestStaticInit() { return 10; }
            mydelegate _mydel = (x) =>//LINQ为什么可以?,从下面可知,LINQ语句只相当于一堆初始化语句的集合
            {
                //int fx = fxs; //error
                return 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);
                }
    
                //二,类型转换:对象转bool
                public 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 test
            class 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;
                        }
                        else
                            return 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 protected
            class 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 = 20
                public 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*2
                    bits.Add((byte)left);
                    x = x >> 1;
                }
            }
            #endregion
            #region IEnumerableAndLinQ
            class 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 xgroups
                          orderby 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无法调用
                {//当基类没有无参构造函数时,必须在初始化列表中初始化所有成员对象,如otestx
                    WriteLine("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 = 120
                    var 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.000
                    Console.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]变成了 10101
                int vn = GetBookNumber(2);
                vn = 202; //_bookNum[2]未变,仍为3
    
                ref 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]均为null
                for (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]; //0
                var 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 only
    
                var llst = new LinkedList<int>();//这个才是链表,而list就像是c++的vector
            }
            #endregion
            #endregion
    
            #region 2018.7.31
            #region JSON
            void 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 await
    
            public 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); //线程1
                        Thread.Sleep(100);
                    }
                });
                var task1 = Task.Run(() =>
                {
                    for (int i = 0; i < 10; ++i)
                    {
                        WriteLine(Thread.CurrentThread.ManagedThreadId + ":task1>>" + i);//线程2
                        Thread.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);//线程3
                        Thread.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); //线程1
                        Thread.Sleep(100);
                    }
                });
                var task1 = Task.Run(() =>
                {
                    for (int i = 0; i < 10; ++i)
                    {
                        WriteLine(Thread.CurrentThread.ManagedThreadId + ":task1>>" + i);//线程2
                        Thread.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);//线程3
                        Thread.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 异步调用Invoke
    
            delegate 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 = 10
                lst1.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: 0x0000000002472dc0
                WriteLine("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-synchronization
            static void TestWaitHandle()
            {
                //自动重置事件
                //一次只能激活一个线程,因为一旦激活后信号被自动置为了false
                var 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); //wrong
                md = 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; //7
                object 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.14
            static 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
        
    }
  • 相关阅读:
    redis集群报错:(error) MOVED 5798 127.0.0.1:7001
    20190829小记
    20181114小结记录
    遇到的面试题记录
    机器学习-KNN算法原理 && Spark实现
    机器学习-KMeans算法原理 && Spark实现
    大数据开发-生产中遇到的10个致命问题
    大数据开发-Spark-闭包的理解
    大数据开发-Spark-共享变量之累加器和广播变量
    大数据开发-Spark-RDD的持久化和缓存
  • 原文地址:https://www.cnblogs.com/timeObjserver/p/9473538.html
Copyright © 2020-2023  润新知