1 using System;
2 using System.Collections.Generic;
3 //using System.Linq;
4 using System.Text;
5 using System.Diagnostics;
6 using System.IO;
7 using static System.Console;
8 using System.Linq;
9 using System.Runtime.InteropServices;
10 using System.Threading;
11
12 namespace ConsoleApplication1
13 {
14 class Program
15 {
16 [DllImport("dltest.dll", EntryPoint ="Print")]
17 static extern void xPrint(int x);
18 #region old-test
19
20 //////////////////////////////////////////////////////////////////
21 static void TestStreamReadWrite()
22 {//一个流不能兼备读写两种操作,不知道为什么,这不合理
23 string s1 = "你好啊ABC";
24
25 var t = "你好啊ABC".Length;
26 //关于编码注意几点:
27 //1,sizeof(char) 等于 2
28 //2,str.Length 是以元素个数算的,不是按字节算的,如 "你好啊ABC” length = 6
29 //3,c#在VS的默认编码为 Encoding.Default, 该编码下汉字占两字节,非汉字占1字节,通过查看ms中的字节数据可知
30 //4,string 类型写入任何buffer时都是先写长度,一般为1字节,再写字节数据,如下
31 var sz = sizeof(char); //2, 注意char占2字节
32 var szb = sizeof(bool); //1
33
34 var ms = new MemoryStream();
35 var writer = new BinaryWriter(ms, Encoding.UTF7);
36 writer.Write(s1);
37 ms.Close();
38 writer.Close();
39
40 var ms2 = new MemoryStream(ms.GetBuffer());
41 var reader = new BinaryReader(ms2, Encoding.UTF8);
42 var s2 = reader.ReadString();
43
44 }
45
46 //////////////////////////////////////////////////////////////////
47 static void TestEncoding()
48 {
49 string s1 = "你好啊ABC";
50
51 //汉字乱码问题,汉字必须使用2个以上字节才能表示
52 //编码方式
53 //1,ASCII码,只有一个字节,不能正确表示汉字,出现乱码,可以正确表示数字和字母符号
54 //2,UNICODE,任何符号都用2个字节表示,因此可以表示汉字和任意符号
55 //3,UTF8,变字节的编码,可以正确表示任何字符和汉字,各国语言
56 //4,GB2312编码,国标码,主要是为汉字服务的中国编码,汉字占两字节,字母数字占1字节
57 //5,default编码,在国内, 般就是GB2312
58 Encoding.Default.GetBytes(s1);
59 var bytes = Encoding.GetEncoding("GB2312").GetBytes(s1);
60 var len = bytes.Length;
61 var bts = new byte[10 + len];
62 Array.ConstrainedCopy(bytes, 0, bts, 0, len);
63
64 var s2 = Encoding.GetEncoding("GB2312").GetString(bts).TrimEnd('\0');
65 string s3 = "\0hello/0/0dddddd".TrimStart('\0');//!!!!!!!!!!!!!!!!!!!!!!!!!!!!
66
67 }
68
69 #region 计算机中数据的存储
70 //////////////////////////////////////////////////////////////////
71 static void TestTypeConvert()
72 {//把一个有符号数转为无符号后再转回来值保持不变,以下以1字节为例
73 //原理:计算机中符点数都是有符号的,不存在这种转变,只剩下整数,
74 //真值:绝对值的二进制值,如-1的真值为 00000001
75 //整数是以补码形式存放的,计算机规定了正数的补码是本身,负数的补码是:符号位不变,真值按位取反再加1
76 //强制转换做的事就是把一个补码看成是有符号还是无符号
77 //有符号数,在计算时:符号位不变,真值按位取反再加1。无符号数直接计算,举例如下:
78 //1,-1 的真值为00000001,补码为 1 111 1111,强转时就是把补码值看作是一个无符数,因此它=255
79 //,再次强转时把它看成有符号数,符号位不管,其余位按位取反加1后是1,因此再次转回了-1
80 //2,-2 的真值为00000010,补码为 1 111 1110,强转时把补码看作无符号数,因此它=254
81 //3,-128真值有点特殊,128的二进制码为1000 0000,第8位是符号位,舍弃,取后面的0,即-128的真值为0
82 //补码经按位取反加1后还是 1 000 0000,强转时看成无符号数即为128
83 //-------------------------------------------
84 //1字节数据和2字节数据进行加法运算时,要进行位扩展,将1字节扩展为2字节
85 //正数扩展时高位补0,负数扩展时高位补1
86 //C#中小于4字节的数据进行运算时会先扩展成int再进行
87 sbyte sb = -127;
88 var b = (byte)(sb);
89 var sb1 = (sbyte)(b);
90 object dx = 10.0f;
91 double dx2 = 33;
92 byte ix = (byte)dx2;
93
94 var t = dx.GetType();
95 Type T = System.Type.GetType(t.FullName, true);
96
97
98 }
99 #endregion
100
101 //////////////////////////////////////////////////////////////////
102 void TestUncheck()
103 {
104 unchecked
105 {//不被编译系统做编译时安全检查
106
107 }
108 }
109
110 static void TestBoxing()
111 {
112 int i = 10;
113 object o = 1;
114 int i2 = (int)o;
115 }
116
117 static void TestReadBytes()
118 {
119 byte[] bts = new byte[4] { 23, 0, 16, 0 };
120 var ms = new MemoryStream(bts);
121 var br = new BinaryReader(ms);
122 var p1 = ms.Position;
123 var ix = br.ReadUInt32();
124 var p2 = ms.Position;
125 Console.WriteLine("num=" + ix);
126 br.Dispose();
127 br.Close();
128 ms.Dispose();
129 ms.Close();
130 }
131
132 static void TestStrEnd()
133 {
134 string str = "abcde\0";
135 var br = new BinaryReader(new MemoryStream(Encoding.ASCII.GetBytes(str)));
136 var b = br.ReadByte();
137 while (b != 0)
138 {
139 Console.WriteLine(b);
140 try
141 {
142 b = br.ReadByte();
143 }
144 catch (System.Exception ex)
145 {
146 Console.WriteLine("未发现字符串结束符");
147 break;
148 }
149 }
150 }
151
152 static void TestBigEndia()
153 {
154 var br = new BinaryWriter(File.Create("f:/testx.dt"), Encoding.ASCII);
155 br.Write((Int16)9);
156 string str = "Stand";
157 br.Write(str);
158 br.Write((Int16)10);
159 br.Write((Int16)70);
160 br.Dispose();
161
162 }
163
164 static void TestChar0()
165 {//注意字符串中0和\0的区别,如 s1="h0ello", s2 = "h\0ello"
166 //s2中的\0是字符串结尾符,除了C#不把它作为结束符外,其它语言都把它作为结束符,如U3D,LUA,C/C++等
167 //而s1中的0仅是一个字符0而已,字符0的ASCII值是0X31=49,'\0'的ASCII值是0
168 //注意这两种0在C#和U3D的API之间切换时容易造成BUG,如:
169 //1, debug.log(s1): "h0ello"
170 //2,debug.log(s2): "h"
171 var s = "hello";
172 s += 0 + ",world";
173 var s1 = "hello";
174 s1 += (char)0 + ",world";
175 var s2 = "hello";
176 s2 += '\0' + ",world";
177 }
178 static void MemTest()
179 {
180
181 }
182 static void ReflectionTest()
183 {//测试两种反射的效率问题
184 //Type.GetType()只能在同一个程序集中使用,typeof则可以跨程序集(assembly)
185 //通过下面的实测,发现typeof是比GetType快40多倍
186 var timer = Stopwatch.StartNew();
187 timer.Start();
188
189 Type tx = Type.GetType("string");
190 var tx1 = Type.GetType("float");
191 timer.Stop();
192
193 Console.WriteLine("T1= " + timer.Elapsed);//0.0000471
194
195 timer.Restart();
196
197 tx = typeof(string);
198 tx1 = typeof(float);
199
200 timer.Stop();
201 Console.WriteLine("T2= " + timer.Elapsed);//0.0000011
202 }
203
204 static void TestDelegate()
205 {
206
207 //类C++11风格:指定初始化容量20,使用初始化列表给部分成员赋值
208 var lst = new List<float>(20) { 1, 3, 4, 20, -2, 9, 0 };
209 for (var i = 0; i < lst.Count; ++i)
210 {
211 //使用下标进行随机访问,说明list不是一个真正的链表,而是类似STL的Vector
212 Console.WriteLine(lst[i]);
213 }
214
215 //public void Sort (Comparison<T> comparison)
216 //public delegate int Comparison<T>(T x, T y);
217
218
219 //这是对调用List<int>.Sort进行排序的写法,其中sort的定义及Comparison委托的定义如上
220 lst.Sort(new Comparison<float>(delegate (float m1, float m2) //委托
221 {
222 return 1;
223 }));
224 lst.Sort(delegate (float m1, float m2) //委托
225 {
226 return 1;
227 });
228 lst.Sort((float m1, float m2) =>//Linq表达式
229 {
230 return 1;
231 });
232 lst.Sort((m1, m2) => //Linq表达式
233 {
234 return 1;
235 });
236
237 }
238
239 static string TestRetStr()
240 {//测试返回字符串是否会复制
241 return "helloworld";
242 }
243
244 static void TestStrRet()
245 {//h1 = h2 = h3说明它们返回的是同一个字符串的引用
246 var s1 = TestRetStr();
247 var s2 = TestRetStr();
248 var s3 = TestRetStr();
249 var h1 = s1.GetHashCode();
250 var h2 = s1.GetHashCode();
251 var h3 = s1.GetHashCode();
252 }
253 static void TestVirtualFuncCall()
254 {
255 var otx = new CTestChildX();
256
257 otx.Update();//输出结果:child,如果注释1处函数不加override,输出结果为:base
258 var oty = new CTestY();
259 oty.Update();
260 oty.OnUpdate();
261
262 }
263 static void TestStrModify()
264 {
265 var s1 = "hello";
266 var s2 = s1;
267 s1 += "world";
268 Console.WriteLine(s2);
269
270 var uns1 = s2.GetHashCode();
271 Console.WriteLine(uns1);
272 }
273
274 static void Tests1()
275 {
276 var s1 = "hello";
277 var uns1 = s1.GetHashCode();
278 Console.WriteLine(uns1);
279
280 }
281
282 #endregion
283
284 #region 2018.3.30
285 #region ref out and template
286 class myTemp<T1, T2>//类入口
287 {
288 public T1 Add(T1 a, T1 b)
289 {//模板类型不能直接相加,必须先转为动态类型,避开编译检查,运行时动态决定类型
290 dynamic da = a;
291 dynamic db = b;
292 return da + db;
293 }
294
295 public void tint<T3>()//注意C++不能这么写,所有模板参数必须由类入口传入
296 {
297 Type t = typeof(T3);
298 WriteLine(t);
299 }
300 }
301
302 delegate void refOutFunc(ref double t1, out double t2);
303 delegate T TemplateDelegate<T, U>(T a, U b);
304 static void TestRefAndOut()
305 {
306 //ref, out 本质上都是引用
307 //fef就为了传给函数使用,必须先初始化,但也可以传出数据,out是为了从函数中传出数据使用,不用初始化
308 refOutFunc rof = delegate (ref double ax, out double bx) {
309 ax = 1; bx = 2;//ref out两种类型的变量都被更改了
310 };
311
312 double x1 = 0, x2;
313 rof(ref x1, out x2);
314 }
315 static void TestTemplate()
316 {
317 var otp = new myTemp<int, int>();
318 otp.tint<object>();
319 }
320 static T TempFunc<T, U>(T a, U b)
321 {
322 return a;
323 }
324 static void TestBufAligin()
325 {//自定义字节BUF的对齐测试
326 int x = 9;
327 int y = (x + 7) & ~7;
328 WriteLine(y);
329 }
330 #endregion
331
332 #endregion
333
334 #region 2018.4.9
335
336 //BUG??????
337 //使用StopWatch测试运行时间
338 //两段测试A和B
339 //测试结果受测试顺序影响,后测要比先测耗时长了许多
340
341 static void TestKeyIntStr()
342 {//
343 var idict = new Dictionary<int, string>();
344 var sdict = new Dictionary<string, string>();
345
346 for (int i = 0; i < 1000000; i++)
347 {
348 var key = i * 2 + 1;
349 var v = i * i + "";
350 idict.Add(key, v);
351 sdict.Add(key + "", v);
352 }
353
354 //测试 A
355 var t1 = 100000 * Test1(idict);
356
357 //测试 B
358 var t2 = 100000 * Test2(sdict);
359
360 Console.WriteLine("t1: {0},t2: {1}", t1, t2);
361 //Console.WriteLine("dt1: {0},dt2: {1}", dt1, dt2);
362 }
363 static float Test1(Dictionary<int, string> dict)
364 {
365 var timer = new Stopwatch();
366 timer.Start();
367 var it = dict[2001];
368 var t1 = timer.ElapsedTicks;
369 timer.Stop();
370 return (float)((float)t1 / Stopwatch.Frequency);
371 }
372
373 static double Test2(Dictionary<string, string> dict)
374 {
375 var timer = new Stopwatch();
376 timer.Start();
377 var it = dict["2001"];
378 var t1 = timer.ElapsedTicks;
379 timer.Stop();
380 return (float)((float)t1 / Stopwatch.Frequency);
381 }
382 #endregion
383
384 #region 2018.7.7
385 #region 数组的数组,二维数组
386 static int[] returnArray()
387 {
388 //数组是引用类型,分配在堆上
389 int[] arr = { 1, 2, 3, 4 }; //虽然这样写,其实等价于int[] arr = new int[]{1,2,3,4};
390 return arr; //返回一个数组对象
391 }
392 static void TestArray() {
393
394 //1,一维数组
395 char[] arr = new char[2] { 'a', 'b' }; //必须全部初始化,或不初始化
396 int[] iarr = new int[2] { 0, 1 };
397 char[] sarr = new char[3];
398
399 //2,数组的数组,锯齿数组
400 char[][] d2arr = new char[2][];
401 d2arr[0] = new char[30];
402 d2arr[1] = new char[2] { 'a', 'b' };
403 d2arr[0][1] = 'x';
404
405 //3,二维数组,矩阵
406 int[,] i2arr = new int[2, 3];
407 for (var i = 0; i < 2; ++i)
408 {
409 for (var j = 0; j < 3; ++j)
410 {
411 i2arr[i, j] = i * 3 + j;
412 }
413 }
414 }
415 #endregion
416 #region 字段初始化无法使用非静态(字段、方法、属性)
417 delegate int mydelegate(int x);
418 //-------------------------------------------------------------------------
419 //字段初始化无法使用非静态(字段、方法、属性)
420 //-------------------------------------------------------------------------
421 float fxs;
422 static float sfxs;
423 //float fxs2 = fxs; //error
424 float fxs3 = sfxs; //right,可用静态字段初始化
425 float fxs4 = TestStaticInit(); //right,调用静态函数初始化
426 static int TestStaticInit() { return 10; }
427 mydelegate _mydel = (x) =>//LINQ为什么可以?,从下面可知,LINQ语句只相当于一堆初始化语句的集合
428 {
429 //int fx = fxs; //error
430 return 20;
431 };
432
433 #endregion
434 #region 默认访问修饰符
435 //1,名字空间中,最外层类及接口的默认修饰符为internal,也就是本程序集可访问
436 //2,类中,变量,成员,类中类的默认修饰符为private
437 //3,结构中,同类
438 //4,接口中,所有方法和属性都为public,接口中只能有方法,不能有变量
439 interface IMyinterface
440 {//接口中可以有方法,抽象属性,不可以有变量
441 int Id { get; } //抽象属性,公有
442 void Fly(); //方法,公有
443 }
444 #endregion
445 #region 类模板继承
446 class CTClass<t1, t2, t3> //多个where的写法
447 where t1 : struct //必须是值类型
448 where t2 : class //必须是引用类型
449 where t3 : new() //必须有无参构造函数
450 {
451 float fx, fy;
452 public static t1 Add(t1 a, t1 b)
453 {
454 return (dynamic)a + (dynamic)b;
455 }
456 }
457
458 //模板继承的几种方式
459 //1,全特化
460 class CDTClass : CTClass<int, CCmpBase, CCmpBase> { }
461
462 //2,原样继承,注意基类的所有约束都要重写一遍
463 class CDTX<t1, t2, t3, t4> : CTClass<t1, t2, t3>
464 where t1 : struct //必须是值类型
465 where t2 : class //必须是引用类型
466 where t3 : new() //必须有无参构造函数
467 { }
468 //3,偏特化,介于二者之间的形态
469 #endregion
470 #region 运算符重载
471 class CCmpBase
472 {//带有默认构造函数
473 float _x;
474 }
475 class CComplex : CCmpBase
476 {
477 float real, image;
478 public CComplex(float real, float image = 0)
479 {
480 this.real = real;
481 this.image = image;
482 }
483
484 //一,类型转换 :数值转对象
485 //CComplex cp = 2.1f 或 CComplex cp; cp = 2.1f;
486 //C#从不调用类型转换构造函数进行类型转换
487 public static implicit operator CComplex(float real)
488 {
489 return new CComplex(real);
490 }
491
492 //二,类型转换:对象转bool
493 public static explicit operator bool(CComplex cp)
494 {
495 return cp.real != 0 && cp.image != 0;
496 }
497
498 //三,类型转换:对象转数值
499 public static implicit operator float(CComplex cp)
500 {
501 return cp.real;
502 }
503
504 //四,算术运算符重载 : +,-,*,/,%等
505 //c#的运算符重载全部为静态函数,因此没有隐含参数
506 //而C++运算符重载时可以重载为友元,绝大多数重载为类的成员函数,因此基本都有一个隐含参数(对象本身)
507 public static CComplex operator +(CComplex a, CComplex b)
508 {
509 return new CComplex(a.real + b.real, a.image + b.image);
510 }
511 public static CComplex operator ++(CComplex cp)
512 {
513 cp.real++;
514 cp.image++;
515 return cp;
516 }
517
518 //五,不支持的运算符重载
519 //1,不允许重载=运算符, C++可以,都不允许重载+=之类的
520 //2,不允许重载括号()运算符
521 //3,不允许重载[]运算符,因为它是索引器
522 //public static implicit operator () (CComplex cp)
523 //{
524 // return a;
525 //}
526
527 void TestPrivate()
528 {
529 var cp = new CComplex(1, 3);
530 cp.real = 20;
531 cp.image = 30.0f;
532 }
533 public void PrintInfo()
534 {
535 WriteLine("real:{0},image:{1}", real, image);
536 }
537 }
538 static void TestOperatorOverload()
539 {
540 CComplex cp = new CComplex(1, 1);
541
542 //1,同时支持前后向++,【不同于C++】
543 cp++;
544 ++cp;
545
546 //2,但不允许连++, 【不同于C++】
547 //cp++++或 ++++cp
548
549 cp.PrintInfo();
550
551 //3,支持连续+,【同于C++】
552 CComplex cp1 = new CComplex(1, 1);
553 var cpadd = cp + cp1 + cp1 + cp1;
554 cpadd.PrintInfo();
555 //类型转换运算符
556 cp = 2.1f;
557
558 //类型转换运算符
559 //C++中是调用类型转换构造函数,而不是运算符重载
560 CComplex cp2 = 1.0f;
561
562 }
563 #endregion
564 #endregion
565
566 #region 2018.7.11
567 #region 两数相加函数模板实现
568 static T MaxNum<T>(T a, T b)
569 {
570 return ((dynamic)a > (dynamic)b) ? a : b;
571 }
572 #endregion
573 #region thread lock
574 //thread test
575 class Account
576 {
577 private object thisLock = new object();
578 int balance;
579 Random r = new Random();
580
581 public Account(int initial)
582 {
583 balance = initial;
584 }
585
586 int Withdraw(int amount)
587 {
588 if (balance < 0)
589 {
590 throw new Exception("Negative Balance");
591 }
592
593 lock (thisLock)
594 {
595 if (balance > amount)
596 {
597 WriteLine("before-withdraw: " + balance);
598 WriteLine("amount to withdraw: " + amount);
599 balance -= amount;
600 WriteLine("after withdraw: " + balance);
601 return amount;
602 }
603 else
604 return 0; //transaction rejected
605 }
606 }
607
608 public void DoTransactions()
609 {
610 for (int i = 0; i < 100; ++i)
611 {
612 Withdraw(r.Next(1, 100));
613 }
614 }
615
616 }
617
618 static void TestObjectLock()
619 {
620 Account acc = new Account(1000);
621 Thread[] threads = new Thread[10];
622 for (int i = 0; i < 10; ++i)
623 {
624 threads[i] = new Thread(acc.DoTransactions);
625 }
626 for (int i = 0; i < 10; ++i)
627 {
628 threads[i].Start();
629 //threads[i].Join();
630 }
631
632
633 }
634 #endregion
635 #region derive protected
636 class A
637 {
638 float fxPrivate;
639 protected int nProtected;
640 protected A(int x) { }
641 }
642
643 class B : A //c++的公有继承
644 {
645 B(String name, int x) : base(x) { }
646
647 protected int nProtected;
648 void TestDerive()
649 {//这里的规则与C++完全一样:
650 //1,子类不能访问基类的私有成员,可以访问基类的保护和公有成员
651 //2,保护成员可以在本类中访问(不一定是本对象中)
652 nProtected = 20;
653 base.nProtected = 10;
654 var ob = new B("b", 1);
655 ob.nProtected = 30; //类中访问类的保护成员,但不是本对象的成员
656
657 }
658 }
659 #endregion
660 #endregion
661
662 #region 2018.7.12
663 #region 常量和静态变量静态类readonly
664 //----------------------------------------------------------------------
665 //常量和静态变量,静态类
666 //----------------------------------------------------------------------
667 //类的静态变量和常量,都属于类而不属于对象,不能用对象来调用,只能用类名调用
668 //这不同于C++,是更合理的设计
669 //常量的值在类定义时就确定了,不因对象而不同,因此存放在类中更合理
670 class CNormclass
671 {
672 class CInclass
673 {
674 public float fx = 20;
675 }
676 public int _id;
677 public const string cname = "CNormalclass";
678
679 //1,常量仅能修饰 :数字,bool,字符串,null引用
680 //不能像C++那样定义一个常量对象,这真是太悲哀了,因为很多时候这可以加速数据传递,增加安全性
681 //由于这个原因,C#的List.ToArray每次都只能返回一个内部数组的拷贝,因此使用list存储数量较大较复杂的数据时
682 //不要轻易使用ToArray,直接用List就行了,它也支持下标索引方式取数组元素
683 const CInclass lst = null;
684
685 //2,readonly也不能实现常量对象的效果
686 //readonly仅表示变量本身不能被赋值,但不阻止通过对象变量更改对象内的字段
687 //onc.readonlyobj.fx = 20
688 public float fx = 20;
689
690 private readonly CInclass readonlyobj = new CInclass();
691
692 public static void Test()
693 {
694 //1,不能调用非静态字段或方法
695 //this._id = 20; //error,没有this指针
696
697 //2,可以调用常量字段
698 var lname = cname;
699
700 var onc = new CNormclass();
701
702 //私有变量在类的静态方法也可以访问
703 //2,虽然不能更改readonlyobj本身的值,却可以更改其内部成员的值,这就是readonly的作用
704 onc.readonlyobj.fx = 20;
705 }
706 }
707 static class C712//类中类,默认为私有
708 {//静态类不能实例化,且只能声明:常量,静态常量,静态属性,静态方法
709 public const int constX = 20; //1,常量
710 public static int staticX = 0; //2,静态常量
711 public static int ix { set; get; } //3,静态属性
712
713 //一,【静态类中不能定义实例化字段】
714 //public int _id;
715
716 //二,【静态类中不能定义实例化字段】
717 //void Ctest(){ //【error: 静态类中不能定义实例化方法】
718 // this._id = 20;
719 //}
720
721 static void Test()//4,静态方法
722 {
723 //三,【静态方法中不能调用非静态变量或方法,因为没有this指针】
724 //_id = 20; //error
725
726 //四,【可以调用常量字段,这与C++不同】
727 var c = constX;
728 }
729
730 }
731 public const int ixd = 20;
732 public static float fx = 20;
733 public void Testff()
734 {
735 fx = 30; //等价于Program.fx = 30,而不是 this.fx = 30;
736 Program.fx = 30;
737 var tx = C712.constX;
738 C712.staticX = 30;
739 var ix = Program.ixd;
740
741 //var oc7 = new C712(); //error 静态类不能创建实例
742 }
743 #endregion
744 #region 事件和委托
745 //--------------------------------------------------------------
746 //event -test
747 //--------------------------------------------------------------
748 //使用event的好处,与delegate的区别:
749 //event 本质上是一个委托,是做了一些安全措施的委托
750 //1,event 定义的委托只允许 +=操作,不允许=赋值,这样防止事件被误清空,delegate则没有这些限制
751 //2,event 定义的委托只能在本类中调用,可以防止外部触发,delegate没有这些限制
752 //3,不使用事件,delegate方式完全可以实现类似限制,通过私有变量和公有函数结合方式
753 class EventTest
754 {
755 public delegate void Delx(string s = "");
756 Delx _delegate; // 私有委托,防止外部调用
757 public event Delx _event; //公有事件,给外部通过+=注册使用,但_event()函数只能在本类调用,不能在类外调用
758
759 //-------------------------------------------------------------
760 //1 ,委托方式
761 //-------------------------------------------------------------
762 //(1)外部调用eventTest.AddListener(func)方式注册事件
763 public void AddListener(Delx callback)
764 {
765 _delegate += callback;
766 }
767 //(2)本类对象调用此函数触发事件
768 void DelegateBrocast()
769 {
770 _delegate("delegate"); //回调,触发事件
771 }
772
773 //-------------------------------------------------------------
774 //2,事件方式
775 //-------------------------------------------------------------
776 //(1)外部使用 _event += 方式注册回调函数
777 //(2)本类对象调用此函数触发事件
778 void EventBrocast()
779 {
780 _event("event");//回调,触发事件
781 }
782 }
783 class Listener
784 {
785 public void OnEvent(string s)
786 {
787 WriteLine("on-event---------------" + s);
788 }
789 }
790 static void TestEventAndDelegate()
791 {
792 Listener l1 = new Listener();
793 EventTest test = new EventTest();
794
795 //1,事件方式
796 test._event += l1.OnEvent; //注册事件
797 //test._event = l1.OnEvent; //编译错误,事件只能使用+=,防止事件被清空
798 //test._event("event"); //编译错误,事件不能在类外调用,事件只能由其所在类调用
799
800 //2,委托方式
801 test.AddListener(l1.OnEvent); //注册委托,通过函数对委托进行注册,因委托是私有的,可防止直接操作 test._delegate()
802 }
803
804 #endregion
805 #region 文件和目录
806 static void FileAndDirectory()
807 {
808 //-------------------------------------------------------------------------
809 //文件对象的相关操作
810 //-------------------------------------------------------------------------
811 //方式一,使用工具类:File类,不需生成对象
812 var file = File.Open("f:/test.txt", FileMode.Create, FileAccess.ReadWrite);
813 //方式二,通过FileStream的对象
814 var filestream = new FileStream("f:/test._txt", FileMode.Create, FileAccess.ReadWrite);
815
816 //-------------------------------------------------------------------------
817 //目录文件相关操作
818 //-------------------------------------------------------------------------
819 //方式一,实例化DirectoryInfo类
820 var dir = new DirectoryInfo("f:/tolua");
821 //(1)获取目录
822 foreach (var d in dir.GetDirectories("*.*", SearchOption.AllDirectories))
823 {
824 WriteLine(d.FullName);
825 }
826 //(2)获取文件
827 foreach (var fileinfo in dir.GetFiles("*.*", SearchOption.AllDirectories))
828 {
829 WriteLine(fileinfo.FullName);
830 }
831
832 //方式二,使用工具类: Directory类,不需生成对象
833 //(1)获取目录
834 var dirs = Directory.GetDirectories("f:/tolua", "*.*", SearchOption.AllDirectories);
835 //(2)获取文件
836 dirs = Directory.GetFiles("f:/tolua", "*.*", SearchOption.AllDirectories);
837
838 for (int i = 0; i < dirs.Length; ++i)
839 {//打印输出
840 WriteLine(dirs[i]);
841 }
842
843 }
844 #endregion
845 #endregion
846
847 #region 2018.7.17
848 #region 计算机中浮点数的存储
849 static void TestFloat()
850 {
851 using (var ms = new MemoryStream())
852 {
853
854 using (var br = new BinaryWriter(ms))
855 {
856 br.Write(125.5f);
857 var bytes = ms.GetBuffer();
858 }
859 }
860 unsafe
861 {
862 float fx = 125.5f;
863 int* pfx = (int*)(&fx);
864 }
865
866 }
867
868 #endregion
869 #region 位移运算
870 static void TestBitShift()
871 { //----------------------------------------------------------------------------
872 //十进制数转二进制:
873 //1,原理:将数X右移1位,最低位被移出,再左移,得到了数X0,则x-x0即为最低位的值
874 //2,手工算法:根据1的原理,不断的对一个数整除2得余数,了终得到余数序列即是二进制的反向序列
875 //3,左移等价于乘2,右移等价于除2,原理是乘法的竖式算法,
876 // 101
877 //x 010
878 //------- 竖式算法适用于任何进制的加减法和乘法运算
879 // 000
880 //+101
881 //-------
882 // 1010
883 //----------------------------------------------------------------------------
884
885 int x = 7;
886 List<Byte> bits = new List<Byte>(4);
887 while (x != 0)
888 {
889 var left = x - ((x >> 1) << 1);//<=> x - x/2*2
890 bits.Add((byte)left);
891 x = x >> 1;
892 }
893 }
894 #endregion
895 #region IEnumerableAndLinQ
896 class Product
897 {
898 public int cateId;
899 public string name;
900 }
901 class Category
902 {
903 public int id;
904 public string name;
905 }
906 public static void TestIEnumerableAndLinq()
907 {
908 Category[] cates = new Category[]
909 {
910 new Category{id = 1, name = "水果"},
911 new Category{id = 2, name = "饮料"},
912 new Category{id = 3, name = "糕点"},
913 };
914
915 Product[] products = new Product[]
916 {
917 new Product{cateId=1, name = "apple"},
918 new Product{cateId=1, name = "banana"},
919 new Product{cateId=1, name = "pear/梨"},
920 new Product{cateId=1, name = "grape/葡萄"},
921 new Product{cateId=1, name = "pineapple/菠萝"},
922 new Product{cateId=1, name = "watermelon/西瓜"},
923 new Product{cateId=1, name = "lemon/柠檬"},
924 new Product{cateId=1, name = "mango/芒果"},
925 new Product{cateId=1, name = "strawberry/草莓"},
926 new Product{cateId=2, name = "bear/啤酒"},
927 new Product{cateId=2, name = "wine"},
928 new Product{cateId=3, name = "cake"},
929 new Product{cateId=3, name = "basicuit/饼干"},
930
931 };
932 var rets = cates.Where((x) => { return x.id > 1 && x.id < 5; });
933 var iter = rets.GetEnumerator();
934
935 while (iter.MoveNext())
936 {
937 //WriteLine(iter.Current);
938 }
939
940 var set = from c in cates
941
942 //这里只能写一个条件,就是equals,用来关联两个表
943 //并且 c相关的条件只能写在equals左边,p相关条件只能写equals右边
944 join p in products on c.id equals p.cateId
945
946 //这里存放的是 products中的元素合集,而不是cates中的元素合集
947 //如果 from p in products join c in cates on c.id equals p.id into xgroups
948 //则xgroups中放的是cates中的元素集合
949
950 //这里是说将products中cateId等于c.id的所有元素放入一个组xgroups中
951 into xgroups
952 orderby c.id descending //对set中的结果进行降序排列
953
954 //where m > 4 && m < 10 //这里就可以写多个条件了
955
956 //from in 相当于外层循环,join in 相当于内层循环
957 //select在双层循环体中,每执行一次循环,【如果符合条件】,则执行一次结果选择
958 //双层循环完成后,最终将很多条选择提交给set
959 //【注意,如果不符合条件 select不会执行】
960 select new { cate = c.name, grp = xgroups }; //可以生成一个新的对象
961
962 foreach (var p in set)
963 {
964 WriteLine("分组:" + p.cate);
965 foreach (var g in p.grp)
966 {
967 WriteLine(g.cateId + "," + g.name);
968 }
969 }
970 }
971
972 #endregion
973 #region 类和继承
974 class CTestX
975 {
976 public virtual void OnUpdate()
977 {
978 Console.WriteLine("base-on-update");
979 }
980 public virtual void OnUpdate2()
981 {
982 Console.WriteLine("base-on-update2");
983 }
984 public void Update()
985 {
986 this.OnUpdate(); //注释1,如果子类有overide则调用子类的,否则调用自己的
987 }
988
989 public CTestX()
990 {
991
992 }
993 protected CTestX(float fx)
994 {
995 WriteLine("CTestX");
996 }
997
998 ~CTestX()
999 {
1000 WriteLine("~Ctestx");
1001 }
1002 public float fx;
1003 string name;
1004 }
1005
1006 //子类不能访问基类任何私有的东西,包括方法,字段,属性,但它们都被继承了,属于子类,从实例内存可证
1007 //方法包括构造函数,即当基类是私有构造函数时,子类无法在初始化列表中调用base()来初始化
1008 class CTestChildX : CTestX
1009 {
1010 CTestX otestx;
1011
1012 public CTestChildX() : base(1)//当基类为私有构造时,这里base无法调用
1013 {//当基类没有无参构造函数时,必须在初始化列表中初始化所有成员对象,如otestx
1014 WriteLine("CTestChildX");
1015 }
1016
1017 //注意overide与virtual的区别:
1018 //1,overide : 表明【函数是对基类的重写】 且 【本身是虚函数可被子类重写】
1019 //【函数会与基类、子类发生虚函数机制】
1020 //2,virtual : 仅表明函数是个虚函数,不会与基类发生虚函数机制
1021 //如果子类overide了该函数,则会与子类发生虚函数机制
1022 //3,多级继承中只要有一级没override,虚函数机制就会打断在此层级,见
1023
1024 //override在编译层的机制是重写虚函数表中的函数地址
1025 //即将继承而来的虚函数表中的虚函数地址替换成本类的虚函数地址
1026 public static void TestDerive()
1027 {
1028 // CTestX ox = new CTestChildX();
1029 // ox.OnUpdate(); //base-on-update,无虚函数机制发生
1030 // ox.OnUpdate2(); //child-on-update2,虚函数机制发生
1031 // ox = new CTestY();
1032 // ox.OnUpdate(); //base-on-update,无虚函数机制发生
1033 CTestChildX ocx = new CTestZ();
1034 ocx.OnUpdate(); //grand-child-on-update
1035 }
1036
1037 public override void OnUpdate()
1038 {
1039 Console.WriteLine("child-on-update");
1040 }
1041 public override void OnUpdate2()
1042 {
1043 Console.WriteLine("child-on-update2");
1044 }
1045
1046 ~CTestChildX() //不支持virtual
1047 {
1048 WriteLine("~CTestChildX");
1049 }
1050 }
1051
1052 class CTestY : CTestChildX
1053 {
1054 public override void OnUpdate()
1055 {
1056 Console.WriteLine("grand-child-on-update");
1057
1058 }
1059 }
1060 class CTestZ : CTestY
1061 {
1062 //因为这里的Update不是虚函数,因此
1063 public void OnUpdate()
1064 {
1065 Console.WriteLine("grand-grand-child-on-update");
1066
1067 }
1068 }
1069
1070
1071 struct CTX
1072 {
1073 void Test() {//不支持C++的const语法
1074 }
1075 }
1076
1077 //1,不能继承结构,可以实现接口,
1078 //2,不能有虚函数
1079 struct CCTX //: CTX
1080 {
1081 public void Test()
1082 {
1083
1084 }
1085 }
1086
1087 #endregion
1088 #region 字符串格式化
1089 static void TestStrFormat()
1090 {
1091 var str = Console.ReadLine();
1092 while (str != "exit")
1093 {
1094 int ix;
1095 Int32.TryParse(str, out ix); //ix = 120
1096 var f1 = string.Format("{0 :d5}", ix); //"00120"
1097 var f2 = string.Format("{0,-10:d5}", ix);//"00120 "
1098 var f3 = string.Format("{0:x}", ix); //16进制输出到字符串
1099 var f4 = string.Format("{0:0.000}", ix);//浮点数 120.000
1100 Console.WriteLine("-----------begin-------------");
1101 Console.WriteLine(f1);
1102 Console.WriteLine(f2);
1103 Console.WriteLine(f3);
1104 Console.WriteLine(f4);
1105 Console.WriteLine("------------end-------------");
1106
1107 str = Console.ReadLine();
1108 }
1109 }
1110 #endregion
1111 #endregion
1112
1113 #region 2018.7.25
1114 #region 引用返回值(不是右值引用)
1115 static int[] _bookNum = new int[] { 1, 2, 3, 4, 5, 6 };
1116 static ref int GetBookNumber(int i)
1117 {
1118 int x = 10;
1119 return ref _bookNum[i];
1120 }
1121 static void TestRefReturn()
1122 {
1123 ref int rfn = ref GetBookNumber(1);
1124 rfn = 10101; //_bookNum[1]变成了 10101
1125 int vn = GetBookNumber(2);
1126 vn = 202; //_bookNum[2]未变,仍为3
1127
1128 ref int x = ref vn;
1129 }
1130 #endregion
1131 #region 索引器
1132 class mylist<T>
1133 {
1134 const int defaultCap = 4;
1135 T[] items;
1136 int count;
1137 int cap = defaultCap;
1138 public mylist(int cap = defaultCap)
1139 {
1140 if (cap != defaultCap)
1141 this.cap = cap;
1142 items = new T[cap];
1143 }
1144 public T this[int idx] {
1145 set {
1146 items[idx] = value;
1147 }
1148 get {
1149 return items[idx];
1150 }
1151 }
1152
1153 }
1154 enum Color
1155 {
1156 red,
1157 green,
1158 blue,
1159 yellow,
1160 cyan,
1161 purple,
1162 black,
1163 white,
1164 }
1165
1166 static void TestIndexer(Color clr = Color.black)
1167 {
1168 mylist<string> lst = new mylist<string>();
1169 lst[1] = "hello";
1170 }
1171 #endregion
1172 #region 部分类
1173 //部分类的作用是可以把一个庞大的类拆分到多个文件,每个文件实现一部分
1174 //而不是实现像C++那样将声明与实现分开
1175 //若要实现声明(接口)与实现分开,应该使用抽象类或接口
1176 partial class CPartclass
1177 {
1178 public void ShowName() {
1179 WriteLine("show name");
1180 }
1181 }
1182
1183 partial class CPartclass
1184 {
1185 public void ShowAge(){
1186 WriteLine("show age");
1187 }
1188 }
1189 static void TestPartclass()
1190 {
1191 CPartclass opc = new CPartclass();
1192 opc.ShowName();
1193 opc.ShowAge();
1194 }
1195 #endregion
1196 #region 动态分配对象数组C#与C++的区别
1197 struct xobject
1198 {
1199 public float fx, fy, fz; //全是public的
1200 }
1201 static void TestDynamicAllocInCSharpCpp()
1202 {
1203 //1,对于引用类型数组,需要两步才能完成,因为数组中存放的是对象的引用
1204 //1.1 c#中
1205 xobject[] arr = new xobject[2];//这时候,只是分配了一个引用数组,arr[0],arr[1]均为null
1206 for (int i = 0; i < 2 ; i++)
1207 {
1208 arr[i] = new xobject(); //为数组中每个引用申请对象
1209 }
1210
1211 //1.2 c++中
1212 //xobject** pp = new xobject*[2];
1213 //pp[0] = new xobject();
1214 //pp[1] = new xobject();
1215
1216 //2 对于值类型数组,则只需一步,因为数组中放的就是值,这在C#与CPP中都一样
1217 //2.1 C#中
1218 int[] iarr = new int[2];
1219 var a0 = iarr[0]; //0
1220 var a1 = iarr[1]; //0
1221
1222 xobject[] varr = new xobject[3];
1223 varr[0].fx = 0.1f;
1224 varr[1].fy = 2.5f;
1225 varr[2].fz = 12;
1226
1227 //2.2,在C++中
1228 //xobject* pobjs = new xobject[2]; //每个数组元素都是一个值类型对象
1229 //pobjs[0].fx = 20;
1230 }
1231 #endregion
1232 #region Object?语法
1233 static void TestobjAsk()
1234 {
1235 object obj = "hello";
1236 WriteLine(obj?.ToString());//如果obj不为null则调用tostring
1237 }
1238 #endregion
1239 #region C#默认字符编码及系统默认编码
1240 //默认编码为unicode,字符串本身的编码并不重要,字节读写时指定的编码才重要,如下面的BinaryWriter
1241 //Encoding.Default是当前系统的默认编码,并不是c#字符串的默认编码
1242 //Encoding.Default规则:汉字2字节,其它1字节
1243 static void TestDefaultStrEncoding()
1244 {
1245 string str = "hdd好";
1246
1247 using (var ms = new MemoryStream())
1248 {
1249 using (var br = new BinaryWriter(ms, Encoding.Default))
1250 {
1251 br.Write(str);
1252 var len = ms.Length-1;
1253 WriteLine(len);
1254
1255 }
1256 }
1257 }
1258 #endregion
1259 #region 属性attribute和反射
1260 class ReflectableClass
1261 {
1262 public float fx;
1263 public string str;
1264 //static const int x = 20; //这在C++中是可以的
1265 public void Printstr(string str, int idx)
1266 {
1267 WriteLine(str + ":" + idx);
1268 }
1269 }
1270 static void TestReflect()
1271 {
1272
1273 ReflectableClass ox = new ReflectableClass();
1274 Type t = typeof(ReflectableClass);//Type.GetType("ConsoleApplication1.Program.ReflectableClass");//ox.GetType();
1275 var tname = t.GetField("name");
1276 var tfx = t.GetField("fx");
1277 var func = t.GetMethod("Printstr", new Type[] {typeof(string),typeof(int) });
1278 func.Invoke(ox, new object[] { "helloworld", 1 });
1279
1280
1281 Type Ts = Type.GetType("System.String");
1282 var fs = Ts.GetMethod("Substring", new Type[] { typeof(int), typeof(int) });
1283 var subs = fs.Invoke("hello world", new object[] { 1, 5 });
1284 WriteLine(subs);
1285 }
1286
1287 static void TestAttribute()
1288 {
1289
1290 }
1291
1292 #endregion
1293 #endregion
1294 #region JSON
1295 void TestJson()
1296 {
1297
1298 }
1299
1300 #endregion
1301 #region CPP与CS间数据传递转换
1302
1303 #endregion
1304 #region 线程
1305 #endregion
1306 #region 线程池
1307 #endregion
1308 #region 任务
1309 #endregion
1310 #region 程序集
1311 #endregion
1312 #region 多线程调试
1313 #endregion
1314 #region 扩展方法测试
1315 static void TestExtMethod()
1316 {
1317 ExtTargetCls oet = new ExtTargetCls();
1318 oet.methodExt(100);
1319 WriteLine(oet.sum);
1320 }
1321 #endregion
1322 class CMyList
1323 {
1324 //readonly仅表示变量本身不能被赋值,但不阻止通过对象变量更改对象内的字段
1325 //on._id = 100 //ok
1326 //on = new CNormclass() //error
1327
1328 public readonly int[] rarr = { 1, 2, 3, 4 };
1329 public readonly int rix = 30; //可在初始化时赋值
1330 public readonly CNormclass on = new CNormclass();
1331 public CMyList()
1332 {
1333 rix = 1; //可在构造函数中赋值
1334 }
1335 public int[] toArray()
1336 {
1337 return rarr;
1338 }
1339
1340 public void Clear()
1341 {
1342 for(var i=0; i < rarr.Length; ++i)
1343 {
1344 rarr[i] = 0;
1345 }
1346 }
1347 public static implicit operator CMyList(int ix)
1348 {
1349 return new CMyList();
1350 }
1351
1352 }
1353
1354 // ctrl + w, t 可以察看所有待做任务
1355 static void Main(string[] args)
1356 {
1357 TestExtMethod();
1358 //TestReflect();
1359 //TestDefaultStrEncoding();
1360 //TestDynamicAllocInCSharpCpp();
1361 //TestPartclass();
1362 //TestRefReturn();
1363 //TestOperatorOverload();
1364 // CTestChildX.TestDerive();
1365 //TestFloat();
1366
1367 //var arr = returnArray();
1368
1369 }
1370
1371 }
1372 #region 扩展方法
1373 sealed class ExtTargetCls
1374 {
1375 public float sum = 10;
1376 }
1377 //扩展方法必须在顶级静态类中定义,不能是内部类
1378 //能不能通过扩展方法来修改类库以达到不法目的? 不能,因为扩展方法只能修改类的公有成员
1379 static class ExtentMethod
1380 {
1381 public static void methodExt(this ExtTargetCls target, float add)
1382 {
1383 target.sum += add;
1384 }
1385 }
1386 #endregion
1387 }