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
    
}
原文地址:https://www.cnblogs.com/timeObjserver/p/9473538.html