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); // 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[ + len];
Array.ConstrainedCopy(bytes, , bts, , len); var s2 = Encoding.GetEncoding("GB2312").GetString(bts).TrimEnd('\0');
string s3 = "\0hello/0/0dddddd".TrimStart('\0');//!!!!!!!!!!!!!!!!!!!!!!!!!!!! } #region 计算机中数据的存储
//////////////////////////////////////////////////////////////////
static void TestTypeConvert()
{//把一个有符号数转为无符号后再转回来值保持不变,以下以1字节为例
//原理:计算机中符点数都是有符号的,不存在这种转变,只剩下整数,
//真值:绝对值的二进制值,如-1的真值为 00000001
//整数是以补码形式存放的,计算机规定了正数的补码是本身,负数的补码是:符号位不变,真值按位取反再加1
//强制转换做的事就是把一个补码看成是有符号还是无符号
//有符号数,在计算时:符号位不变,真值按位取反再加1。无符号数直接计算,举例如下:
//1,-1 的真值为00000001,补码为 1 111 1111,强转时就是把补码值看作是一个无符数,因此它=255
//,再次强转时把它看成有符号数,符号位不管,其余位按位取反加1后是1,因此再次转回了-1
//2,-2 的真值为00000010,补码为 1 111 1110,强转时把补码看作无符号数,因此它=254
//3,-128真值有点特殊,128的二进制码为1000 0000,第8位是符号位,舍弃,取后面的0,即-128的真值为0
//补码经按位取反加1后还是 1 000 0000,强转时看成无符号数即为128
//-------------------------------------------
//1字节数据和2字节数据进行加法运算时,要进行位扩展,将1字节扩展为2字节
//正数扩展时高位补0,负数扩展时高位补1
//C#中小于4字节的数据进行运算时会先扩展成int再进行
sbyte sb = -;
var b = (byte)(sb);
var sb1 = (sbyte)(b);
object dx = 10.0f;
double dx2 = ;
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 = ;
object o = ;
int i2 = (int)o;
} static void TestReadBytes()
{
byte[] bts = new byte[] { , , , };
var ms = new MemoryStream(bts);
var br = new BinaryReader(ms);
var p1 = ms.Position;
var ix = br.ReadUInt32();
var p2 = ms.Position;
Console.WriteLine("num=" + ix);
br.Dispose();
br.Close();
ms.Dispose();
ms.Close();
} static void TestStrEnd()
{
string str = "abcde\0";
var br = new BinaryReader(new MemoryStream(Encoding.ASCII.GetBytes(str)));
var b = br.ReadByte();
while (b != )
{
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));
string str = "Stand";
br.Write(str);
br.Write((Int16));
br.Write((Int16));
br.Dispose(); } static void TestChar0()
{//注意字符串中0和\0的区别,如 s1="h0ello", s2 = "h\0ello"
//s2中的\0是字符串结尾符,除了C#不把它作为结束符外,其它语言都把它作为结束符,如U3D,LUA,C/C++等
//而s1中的0仅是一个字符0而已,字符0的ASCII值是0X31=49,'\0'的ASCII值是0
//注意这两种0在C#和U3D的API之间切换时容易造成BUG,如:
//1, debug.log(s1): "h0ello"
//2,debug.log(s2): "h"
var s = "hello";
s += + ",world";
var s1 = "hello";
s1 += (char) + ",world";
var s2 = "hello";
s2 += '\0' + ",world";
}
static void MemTest()
{ }
static void ReflectionTest()
{//测试两种反射的效率问题
//Type.GetType()只能在同一个程序集中使用,typeof则可以跨程序集(assembly)
//通过下面的实测,发现typeof是比GetType快40多倍
var timer = Stopwatch.StartNew();
timer.Start(); Type tx = Type.GetType("string");
var tx1 = Type.GetType("float");
timer.Stop(); Console.WriteLine("T1= " + timer.Elapsed);//0.0000471 timer.Restart(); tx = typeof(string);
tx1 = typeof(float); timer.Stop();
Console.WriteLine("T2= " + timer.Elapsed);//0.0000011
} static void TestDelegate()
{ //类C++11风格:指定初始化容量20,使用初始化列表给部分成员赋值
var lst = new List<float>() { , , , , -, , };
for (var i = ; 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 ;
}));
lst.Sort(delegate (float m1, float m2) //委托
{
return ;
});
lst.Sort((float m1, float m2) =>//Linq表达式
{
return ;
});
lst.Sort((m1, m2) => //Linq表达式
{
return ;
}); } 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 = ; bx = ;//ref out两种类型的变量都被更改了
}; double x1 = , 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 = ;
int y = (x + ) & ~;
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 = ; i < ; i++)
{
var key = i * + ;
var v = i * i + "";
idict.Add(key, v);
sdict.Add(key + "", v);
} //测试 A
var t1 = * Test1(idict); //测试 B
var t2 = * 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[];
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[""];
var t1 = timer.ElapsedTicks;
timer.Stop();
return (float)((float)t1 / Stopwatch.Frequency);
}
#endregion #region 2018.7.7
#region 数组的数组,二维数组
static int[] returnArray()
{
//数组是引用类型,分配在堆上
int[] arr = { , , , }; //虽然这样写,其实等价于int[] arr = new int[]{1,2,3,4};
return arr; //返回一个数组对象
}
static void TestArray() { //1,一维数组
char[] arr = new char[] { 'a', 'b' }; //必须全部初始化,或不初始化
int[] iarr = new int[] { , };
char[] sarr = new char[]; //2,数组的数组,锯齿数组
char[][] d2arr = new char[][];
d2arr[] = new char[];
d2arr[] = new char[] { 'a', 'b' };
d2arr[][] = 'x'; //3,二维数组,矩阵
int[,] i2arr = new int[, ];
for (var i = ; i < ; ++i)
{
for (var j = ; j < ; ++j)
{
i2arr[i, j] = i * + 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 ; }
mydelegate _mydel = (x) =>//LINQ为什么可以?,从下面可知,LINQ语句只相当于一堆初始化语句的集合
{
//int fx = fxs; //error
return ;
}; #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 = )
{
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 != && cp.image != ;
} //三,类型转换:对象转数值
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(, );
cp.real = ;
cp.image = 30.0f;
}
public void PrintInfo()
{
WriteLine("real:{0},image:{1}", real, image);
}
}
static void TestOperatorOverload()
{
CComplex cp = new CComplex(, ); //1,同时支持前后向++,【不同于C++】
cp++;
++cp; //2,但不允许连++, 【不同于C++】
//cp++++或 ++++cp cp.PrintInfo(); //3,支持连续+,【同于C++】
CComplex cp1 = new CComplex(, );
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 < )
{
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 ; //transaction rejected
}
} public void DoTransactions()
{
for (int i = ; i < ; ++i)
{
Withdraw(r.Next(, ));
}
} } static void TestObjectLock()
{
Account acc = new Account();
Thread[] threads = new Thread[];
for (int i = ; i < ; ++i)
{
threads[i] = new Thread(acc.DoTransactions);
}
for (int i = ; i < ; ++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 = ;
base.nProtected = ;
var ob = new B("b", );
ob.nProtected = ; //类中访问类的保护成员,但不是本对象的成员 }
}
#endregion
#endregion #region 2018.7.12
#region 常量和静态变量静态类readonly
//----------------------------------------------------------------------
//常量和静态变量,静态类
//----------------------------------------------------------------------
//类的静态变量和常量,都属于类而不属于对象,不能用对象来调用,只能用类名调用
//这不同于C++,是更合理的设计
//常量的值在类定义时就确定了,不因对象而不同,因此存放在类中更合理
class CNormclass
{
class CInclass
{
public float fx = ;
}
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 = ; 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 = ;
}
}
static class C712//类中类,默认为私有
{//静态类不能实例化,且只能声明:常量,静态常量,静态属性,静态方法
public const int constX = ; //1,常量
public static int staticX = ; //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 = ;
public static float fx = ;
public void Testff()
{
fx = ; //等价于Program.fx = 30,而不是 this.fx = 30;
Program.fx = ;
var tx = C712.constX;
C712.staticX = ;
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 = ; 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 = ;
List<Byte> bits = new List<Byte>();
while (x != )
{
var left = x - ((x >> ) << );//<=> x - x/2*2
bits.Add((byte)left);
x = x >> ;
}
}
#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 = , name = "水果"},
new Category{id = , name = "饮料"},
new Category{id = , name = "糕点"},
}; Product[] products = new Product[]
{
new Product{cateId=, name = "apple"},
new Product{cateId=, name = "banana"},
new Product{cateId=, name = "pear/梨"},
new Product{cateId=, name = "grape/葡萄"},
new Product{cateId=, name = "pineapple/菠萝"},
new Product{cateId=, name = "watermelon/西瓜"},
new Product{cateId=, name = "lemon/柠檬"},
new Product{cateId=, name = "mango/芒果"},
new Product{cateId=, name = "strawberry/草莓"},
new Product{cateId=, name = "bear/啤酒"},
new Product{cateId=, name = "wine"},
new Product{cateId=, name = "cake"},
new Product{cateId=, name = "basicuit/饼干"}, };
var rets = cates.Where((x) => { return x.id > && x.id < ; });
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()//当基类为私有构造时,这里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[] { , , , , , };
static ref int GetBookNumber(int i)
{
int x = ;
return ref _bookNum[i];
}
static void TestRefReturn()
{
ref int rfn = ref GetBookNumber();
rfn = ; //_bookNum[1]变成了 10101
int vn = GetBookNumber();
vn = ; //_bookNum[2]未变,仍为3 ref int x = ref vn;
}
#endregion
#region 索引器
class mylist<T>
{
const int defaultCap = ;
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[] = "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[];//这时候,只是分配了一个引用数组,arr[0],arr[1]均为null
for (int i = ; i < ; 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[];
var a0 = iarr[]; //
var a1 = iarr[]; // xobject[] varr = new xobject[];
varr[].fx = 0.1f;
varr[].fy = 2.5f;
varr[].fz = ; //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-;
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", }); 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[] { , });
WriteLine(subs);
} static void TestAttribute()
{ } #endregion
#endregion #region 2018.7.30
#region 扩展方法测试
static void TestExtMethod()
{
ExtTargetCls oet = new ExtTargetCls();
oet.methodExt();
WriteLine(oet.sum);
}
#endregion
#region 元组:同时传递多个不同类型参数
//作用时,可以很方便的,高效的返回一组不同类型的值或对象
//因为是泛型,所以高效
//但是它最多只有8个参数,也就是说不能当作ArrayObject的替代品 static void TestTuple()
{
Tuple<int, float> tupleFunx()
{
return new Tuple<int, float>(, );
} 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 ;
else if (elem < objc.elem)
return -; return ;
}
}
static void TestCompareableobj()
{
var rand = new Random();
ComparableObj<float>[] arrf = new ComparableObj<float>[];
for (var i = ; i < ; ++i)
{
arrf[i] = new ComparableObj<float>(rand.Next(, ));
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 ;
else if (a.elem < b.elem)
return ;
return -;
}); 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 = ;
while (i++ < )
{
Thread.Sleep();
WriteLine("T1>> " + i);
}
});
Thread t2 = new Thread(() =>
{
//t1先执行(<=1000毫秒),t2等待
t1.Join();
//t1,t2同时执行,若上一步t1已完成则不执行
int i = ; while (i++ < )
{
Thread.Sleep();
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();
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();
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());
}
var lst = new List<int>() { , , };
foreach (var v in lst)
{
ifunc(, delegate (int x) {//像lua的回调函数那样使用
return v; //闭包中的v
});
ifunc(, (x) => { return v; });
}
}
#endregion
#region 异步 async await public static async void AsyncFunc()
{
WriteLine(Thread.CurrentThread.ManagedThreadId); //主线程 var task = Task.Run(() =>
{
for(int i= ; i<; ++i)
{
WriteLine(Thread.CurrentThread.ManagedThreadId + ":task>>" + i); //线程1
Thread.Sleep();
}
});
var task1 = Task.Run(() =>
{
for (int i = ; i < ; ++i)
{
WriteLine(Thread.CurrentThread.ManagedThreadId + ":task1>>" + i);//线程2
Thread.Sleep(); }
});
await task; //等待线程1完成
await task1;//等待线程2完成
WriteLine("task and task1 finished");
var task2 = Task.Run(() =>
{
for (int i = ; i < ; ++i)
{
WriteLine(Thread.CurrentThread.ManagedThreadId + ":task2>>" + i);//线程3
Thread.Sleep(); }
});
await task2;//等待线程3完成
Task.WaitAll(task, task1, task2); //无效,因为代码执行到这里时主线程已结束
WriteLine("---------------------------------------------------");
}
public static void AsyncFunc2()
{
WriteLine(Thread.CurrentThread.ManagedThreadId); //主线程 var task = Task.Run(() =>
{
for (int i = ; i < ; ++i)
{
WriteLine(Thread.CurrentThread.ManagedThreadId + ":task>>" + i); //线程1
Thread.Sleep();
}
});
var task1 = Task.Run(() =>
{
for (int i = ; i < ; ++i)
{
WriteLine(Thread.CurrentThread.ManagedThreadId + ":task1>>" + i);//线程2
Thread.Sleep(); }
});
task.Wait();//等待线程1完成
task1.Wait();//等待线程2完成
WriteLine("task and task1 finished");
var task2 = Task.Run(() =>
{
for (int i = ; i < ; ++i)
{
WriteLine(Thread.CurrentThread.ManagedThreadId + ":task2>>" + i);//线程3
Thread.Sleep(); }
});
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();
}
//方式一,采用不使用 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(, , 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 = };
var oc1 = new CInitclass() { name = "jim", age = };
var oc2 = new CInitclass("tim", ) { name = "jim", age = };
var oc3 = new { name = "jim", age = , sex = }; //匿名对象
int[] arr = { , , };
int[] arr2 = new int[] { , , };
List<int> lst = new List<int> { , , };
List<int> lst1 = new List<int>() { , , }; //capacity = 10
lst1.Capacity = ;
WriteLine(lst1.Capacity);
lst1.ForEach((i) => WriteLine(i)); var dict = new Dictionary<int, string> { { , "a" }, { , "b" }, { , "c" } };
var dict1 = new Dictionary<int, string>() { { , "a" }, { , "b" }, { , "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[];
}
static void TestXiebianNibian()
{
object[] ocs = new CNormclass[];
object[] strs = new string[]; //协变的一个陷阱,编译时正常,运行时抛出异常: 类型不匹配
strs[] = ; //泛型类本身的协变(有父子关系,泛型参数相同)
tshape<int>[] tsps = new tshape<int>[];
tshape<CNormclass>[] tcs = new tcircle<CNormclass>[]; //通过函数参数测试普通类的转变
CTestX[] ox = new CTestX[];
xiebianx(ox); }
#endregion
#region 委托中的协变逆变
class XIEBIAN
{
delegate CTestX[] ArrDelegate();
CTestChildX[] func001()
{
return new CTestChildX[];
}
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 = ;
short isa = ;
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 = ;
while (!(int.TryParse(ReadLine(), out num))){}
for(int i=; i < num; ++i)
{
var t = new Thread(tfunc);
t.Start(i);
threads.Push(t);
Thread.Sleep();
} Thread.Sleep(); while(threads.Count > )
{
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 = ;
while (true)
{
Write(".");
Thread.Sleep();
i = i / ;
} }
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(); //调用这个函数,会抛出异常,但若不去捕获,程序就什么都不会发生
//抛出异常与显示异常是不同的
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"), );
var ipendb = new IPEndPoint(IPAddress.Parse("127.0.0.1"), );
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();
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 = ;
int iy = ix ?? ; //
object ob = oa ?? ; //
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 = - < ;
int ix = -;
WriteLine(ix - ); //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 = ;
}
//扩展方法必须在顶级静态类中定义,不能是内部类
//能不能通过扩展方法来修改类库以达到不法目的? 不能,因为扩展方法只能修改类的公有成员
static class ExtentMethod
{
public static void methodExt(this ExtTargetCls target, float add)
{
target.sum += add;
}
}
#endregion }
2018.8.14-C#复习笔记总的更多相关文章
- 2018/2/14 设计模式学习笔记(一) 自己实现ArrayList,LinkedList和Iterator,以及在此过程中对于面向对象,面向接口,还有抽象类的一些思考感悟
因为本人目前为止学习编程不过七个月,所以后面的感悟对于一些大神来说可能嗤之以鼻,但对于一些刚刚入门的萌新来说在理解面向对象的思想上,以及抽象类和接口应该怎么设计等方面应该还是会有所帮助的 首先我们定义 ...
- 2018/3/14 Hadoop学习笔记(一)
首先,什么是Hadoop?为什么它是现在大数据处理最热门的框架呢?(正确来说,现在Hadoop是一个生态圈) Hadoop是apache下一套开源的服务框架,它主要的作用就是利用服务器集群,来对海量数 ...
- FFT/NTT复习笔记&多项式&生成函数学习笔记Ⅲ
第三波,走起~~ FFT/NTT复习笔记&多项式&生成函数学习笔记Ⅰ FFT/NTT复习笔记&多项式&生成函数学习笔记Ⅱ 单位根反演 今天打多校时 1002 被卡科技了 ...
- JZOJ 5812. 【NOIP提高A组模拟2018.8.14】 区间
5812. [NOIP提高A组模拟2018.8.14] 区间 (File IO): input:range.in output:range.out Time Limits: 1000 ms Memo ...
- 树的直径,LCA复习笔记
前言 复习笔记第6篇. 求直径的两种方法 树形DP: dfs(y); ans=max( ans,d[x]+d[y]+w[i] ); d[x]=max( d[x],d[y]+w[i] ); int di ...
- 状压DP复习笔记
前言 复习笔记第4篇.CSP RP++. 引用部分为总结性内容. 0--P1433 吃奶酪 题目链接 luogu 题意 房间里放着 \(n\) 块奶酪,要把它们都吃掉,问至少要跑多少距离?一开始在 \ ...
- 斜率优化DP复习笔记
前言 复习笔记2nd. Warning:鉴于摆渡车是普及组题目,本文的难度定位在普及+至省选-. 参照洛谷的题目难度评分(不过感觉部分有虚高,提高组建议全部掌握,普及组可以选择性阅读.) 引用部分(如 ...
- Java基础复习笔记系列 九 网络编程
Java基础复习笔记系列之 网络编程 学习资料参考: 1.http://www.icoolxue.com/ 2. 1.网络编程的基础概念. TCP/IP协议:Socket编程:IP地址. 中国和美国之 ...
- Java基础复习笔记系列 八 多线程编程
Java基础复习笔记系列之 多线程编程 参考地址: http://blog.csdn.net/xuweilinjijis/article/details/8878649 今天的故事,让我们从上面这个图 ...
随机推荐
- Linux下安装xampp和bugfree
1.BugFree简介 1.1 BugFree的来源 BugFree是借鉴微软的研发流程和Bug管理理念,使用PHP+MySQL独立写出的一个Bug管理系统.简单实用.免费并且开放源代码(遵循GNU ...
- velocity 知识点
velocity 教程: http://www.51gjie.com/javaweb/126 velocity 语法 语法 说明 关键字以#开头 定义数组 ['aaa','bbb'] 变量以$开头 把 ...
- Microsoft Dynamics CRM 2011 中 SQL 语句总结
一.查询用户和团队 插入的类型:OwnerIdType 可以为用户或团队: 1.团队: select top 1 ObjectTypeCode from metadataschema.entity w ...
- Oracle 11G 单机asm安装
http://sugarlovecxq.blog.51cto.com/6707742/1702092/
- TS流的解析
个字节不一定都是有效数据,有一些可能为填充数据). 工作形式: 因为在TS流里可以填入很多种东西,所以有必要有一种机制来确定怎么来标识这些数据.制定TS流标准的机构就规定了一些数据结构来定义.比如: ...
- Javascript作用域学习笔记(三)
看完<你不知道的javascript>上,对作用域的新的理解(2018-9-25更) 一.学习笔记: 1.javascript中的作用域和作用域链 + 每个函数在被调用时都会创建一个 ...
- bzoj 1288: Neighbours
Description 很久以前, 有一个小小的国度, 为了方便, 我们可以把它想象为一个大大的矩形, 矩形的左下角为(0, 0), 右上角为(w, h), 共有(w + 1) * (h + 1)个整 ...
- bzoj4419 发微博
Description 刚开通的SH微博共有n个用户(1..n标号),在短短一个月的时间内,用户们活动频繁,共有m条按时间顺序的记录: ! x 表示用户x发了一条微博: + x y 表示用户x和用 ...
- java获取随机密码
import java.util.Random; public class tests { /** * * author LiuQiang * date 2013-10-14 下午01:13:54 * ...
- ASP.NET Web Pages:帮助器
ylbtech-.Net-ASP.NET Web Pages:帮助器 1.返回顶部 1. ASP.NET Web Pages - 帮助器 Web 帮助器大大简化了 Web 开发和常见的编程任务. AS ...