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 (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 comparison) 216 //public delegate int Comparison (T x, T y); 217 218 219 //这是对调用List .Sort进行排序的写法,其中sort的定义及Comparison委托的定义如上 220 lst.Sort(new Comparison (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 //类入口 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 ()//注意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 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 (); 318 otp.tint