目录
泛型
泛型类
class ClassA<T,A>
{
//T代表一个数据类型,当使用classA进行构造的时候,需要制定T的类型
private T a;
private T b;
private A c;
public ClassA(T a, T b )
{
this.a = a;
this.b = b;
}
public string GetSum()
{
return a +""+ b;
}
}
var o1 = new ClassA<int>(12,34);//当我们利用泛型类构造的时候,需要制定泛型的类型
string s = o1.GetSum();
Console.WriteLine(s);
泛型方法
public static string GetSum<T,T2,T3,T4>(T a, T b)
{
return a + "" + b;
}
Console.WriteLine(GetSum<int,int,int,int>(12,34));
委托
委托基本知识
private delegate string GetAString();//定义了一个委托类型,这个委托类型的名字叫做GetAString
static void Main(string[] args)
{
int x = 40;
string s = x.ToString();//tostring 方法用来把数据转换成字符串
Console.WriteLine(s);
//使用委托类型 创建实例
GetAString a = new GetAString(x.ToString);//a指向了x中的tostring方法
GetAString a = x.ToString;
string s = a();//通过委托实例去调用 x中的tostring方法
string s = a.Invoke();//通过invoke方法调用a所引用的方法
Console.WriteLine(s);//通过委托类型是调用一个方法,跟直接调用这个方法 作用是一样的
//实例2 使用委托类型作为方法的参数
PrintString method = Method1;
PrintStr(method);
method = Method2;
PrintStr(method);
Console.ReadKey();
}
private delegate void PrintString();
static void PrintStr( PrintString print )
{
print();
}
static void Method1() {
Console.WriteLine("method1");
}
泛型委托
//泛型委托
public delegate int Delcompare<T>(T n1,T n2);
person[] people = { new person() {Age=12 },new person() { Age=22} };
string max = GetMax(names, Compare2);
person p = GetMax(people, Compare3);
//返回任意数组中的最大值
public static T GetMax<T>(T[] nums, Delcompare<T> del)//传入一个委托函数,就是比较方法
{
T max = nums[0];
for (int i = 0; i < nums.Length; i++)
{
if (del(max, nums[i]) < 0)
{
max = nums[i];
}
}
return max;
}
public static int Compare1(int n1, int n2)
{
return n1 - n2;
}
public static int Compare2(string n1, string n2)
{
return n1.Length - n2.Length;
}
public static int Compare3(person n1, person n2)
{
return n1.Age - n2.Age;
}
public class person
{
public int Age
{
get;
set;
}
}
Action委托
static void PrintString()
{
Console.WriteLine("hello world.");
}
static void PrintInt(int i)
{
Console.WriteLine(i);
}
static void PrintString(string str)
{
Console.WriteLine(str);
}
static void PrintDoubleInt(int i1, int i2)
{
Console.WriteLine(i1+i2);
}
Action a = PrintString;//action是系统内置(预定义)的一个委托类型,它可以指向一个没有返回值,没有参数的方法
Action<int> a=PrintInt;//定义了一个委托类型,这个类型可以指向一个没有返回值,有一个int参数的方法
Action<string> a = PrintString;//定义了一个委托类型,这个类型可以指向一个没有返回值,有一个string参数的方法 在这里系统会自动寻找匹配的方法
Action<int, int> a = PrintDoubleInt;
a(34, 23);
Console.ReadKey();
//action可以后面通过泛型去指定action指向的方法的多个参数的类型 ,参数的类型跟action后面声明的委托类型是对应着的
Func委托
static int Test1()
{
return 1;
}
static int Test2(string str)
{
Console.WriteLine(str);
return 100;
}
static int Test3(int i, int j)
{
return i + j;
}
Func<int> a = Test1;//func中的泛型类型制定的是 方法的返回值类型
Console.WriteLine(a());
Func<string, int> a = Test2;//func后面可以跟很多类型,最后一个类型是返回值类型,前面的类型是参数类型,参数类型必须跟指向的方法的参数类型按照顺序对应
Func<int, int, int> a = Test3;//func后面必须指定一个返回值类型,参数类型可以有0-16个,先写参数类型,最后一个是返回值类型
int res = a(1, 5);
Console.WriteLine(res);
Console.ReadKey();
多播委托
前面使用的委托都只包含一个方法的调用,但是委托也可以包含多个方法,这种委托叫做多播委托。
使用多播委托就可以按照顺序调用多个方法,多播委托只能得到调用的最后一个方法的结果,一般我们把多播委托的返回类型声明为void。
多播委托包含一个逐个调用的委托集合,如果通过委托调用的其中一个方法抛出异常,整个迭代就会停止。
static void Test1()
{
Console.WriteLine("test1");
//throw new Exception();
}
static void Test2()
{
Console.WriteLine("test2");
}
//多播委托
Action a = Test1;
//a = Test2;
a += Test2;//表示添加一个委托的引用
//a -= Test1;
//a -= Test2;
//if(a!=null)
// a();//当一个委托没有指向任何方法的时候,调用的话会出现异常null
Delegate[] delegates = a.GetInvocationList(); //遍历委托
foreach (Delegate de in delegates)
{
de.DynamicInvoke();
}
匿名函数
有另外一种使用委托的方式,不用去定义一个方法,应该说是使用匿名方法(方法没有名字)。
Func<int,int,int> plus = delegate (int a,int b){
int temp = a+b;
return temp;
};//格式位delegate(参数){方法体}
int res = plus(34,34);
Console.WriteLine(res);
lambda表达式
Func<int, int, int> plus = (arg1, arg2) =>// lambda表达式的参数是不需要声明类型的
{
return arg1 + arg2;
};
Func<int, int> test2 = a => a+1;//lambda表示的参数只有一个的时候,可以不加上括号 当函数体的语句只有一句的时候,我们可以不加上大括号 也可以不加上return语句
观察者设计模式(事件)
事件(Event)是类或对象向其他类或对象通知发生的事情的一种特殊签名的委托.
public event 委托类型 事件名;
有三只动物,猫(名叫Tom),还有两只老鼠(Jerry和Jack),当猫叫的时候,触发事件(CatShout),然后两只老鼠开始逃跑(MouseRun)。
接下来用代码来实现。(设计模式-观察者模式)
class Cat
{
public string name;
public string colour;
public event Action Run; //声明事件委托
public Cat(string name, string colour)
{
this.name = name;
this.colour = colour;
}
public void Coming()
{
Console.WriteLine(this.colour+"的猫"+this.name+" 来了");
this.Run(); //调用事件委托
}
}
class Mouse
{
public string name;
public string colour;
public Cat cat;
public Mouse(string name, string colour,Cat cat)
{
this.name = name;
this.colour = colour;
this.cat = cat;
cat.Run += run; //注册事件
}
public void run()
{
Console.WriteLine(colour+"的猫"+name+":说猫来了,快跑");
}
}
Cat cat1 = new Cat("Tom", "蓝色");
Mouse mouse1 = new Mouse("mouse1", "red", cat1);
Mouse mouse2 = new Mouse("mouse2", "blue", cat1);
Mouse mouse3 = new Mouse("mouse3", "yellow", cat1);
cat1.Coming();//触发事件
LINQ查询语句
//初始化武林高手
var masterList = new List<MartialArtsMaster>()
{
new MartialArtsMaster() {Id = 1, Name = "黄蓉", Age = 18, Menpai = "丐帮", Kongfu = "打狗棒法", Level = 9},
new MartialArtsMaster() {Id = 2, Name = "洪七公", Age = 70, Menpai = "丐帮", Kongfu = "打狗棒法", Level = 10},
new MartialArtsMaster() {Id = 3, Name = "郭靖", Age = 22, Menpai = "丐帮", Kongfu = "降龙十八掌", Level = 10},
new MartialArtsMaster() {Id = 4, Name = "任我行", Age = 50, Menpai = "明教", Kongfu = "葵花宝典", Level = 1},
new MartialArtsMaster() {Id = 5, Name = "东方不败", Age = 35, Menpai = "明教", Kongfu = "葵花宝典", Level = 10},
new MartialArtsMaster() {Id = 6, Name = "林平之", Age = 23, Menpai = "华山", Kongfu = "葵花宝典", Level = 7},
new MartialArtsMaster() {Id = 7, Name = "岳不群", Age = 50, Menpai = "华山", Kongfu = "葵花宝典", Level = 8},
new MartialArtsMaster() {Id = 8, Name = "令狐冲", Age = 23, Menpai = "华山", Kongfu = "独孤九剑", Level = 10},
new MartialArtsMaster() {Id = 9, Name = "梅超风", Age = 23, Menpai = "桃花岛", Kongfu = "九阴真经", Level = 8},
new MartialArtsMaster() {Id = 10, Name = "黄药师", Age = 23, Menpai = "梅花岛", Kongfu = "弹指神通", Level = 10},
new MartialArtsMaster() {Id = 11, Name = "风清扬", Age = 23, Menpai = "华山", Kongfu = "独孤九剑", Level = 10}
};
//初始化武学
var kongfuList = new List<Kongfu>()
{
new Kongfu() {Id = 1, Name = "打狗棒法", Power = 90},
new Kongfu() {Id = 2, Name = "降龙十八掌", Power = 95},
new Kongfu() {Id = 3, Name = "葵花宝典", Power = 100},
new Kongfu() {Id = 4, Name = "独孤九剑", Power = 100},
new Kongfu() {Id = 5, Name = "九阴真经", Power = 100},
new Kongfu() {Id = 6, Name = "弹指神通", Power = 100}
};
//查询所有武学级别大于8的武林高手
//var res = new List<MartialArtsMaster>();
//foreach (var temp in masterList)
//{
// if (temp.Level > 8)
// {
// res.Add(temp);
// }
//}
//1,使用LINQ做查询( 表达式写法)
//查询所有武学级别大于8的武林高手
var res = from m in masterList //自动遍历集合中的每个对象m
where m.Level > 8 && m.Menpai=="丐帮"
select m;
//2,扩展方法的写法
var res1 = masterList.Where(Test);
var res2 = masterList.Where(m=>m.Level>8); //lambda表达式写法
//3,LINQ 联合查询
//取得所学功夫的杀伤力大于90 的武林高手
var res3 = from m in masterList
from k in kongfuList
where m.Kongfu == k.Name && k.Power > 90
select new { master = m, kongfu = k };//选择多个字段
//select m;
//扩展方法用法
var res4 = masterList.SelectMany(k => kongfuList, (m, k) => new { master = m, kongfu = k })
.Where(x => x.master.Kongfu == x.kongfu.Name && x.kongfu.Power > 90);
//4,对查询结果做排序 orderby (descending)
var res5 = from m in masterList
where m.Level > 8
// orderby m.Age descending//加descending就是倒序
orderby m.Level,m.Age //按照多个字段进行排序,如果字段的属性相同,就按照第二个属性排序
select m;
//5,join on 集合联合
var res6 = from m in masterList
join k in kongfuList on m.Kongfu equals k.Name
where k.Power > 90
select m;
//6,分组查询 into groups (把武林高手按照所学功夫分类,看一下那个功夫修炼的人数最多)
var res7 = from k in kongfuList
join m in masterList on k.Name equals m.Kongfu
into groups
select new { kongfu = k, count = groups.Count() };
//7,按照自身字段分组 group
var res8 = from m in masterList
group m by m.Kongfu
into g
select new { count = g.Count(), key = g.Key };//g.Key Key表示是按照那个属性分的组
//8,量词操作符 any all 判断集合中是否满足某个条件或者全部满足
bool res9 = masterList.Any(m => m.Menpai == "长留");
Console.WriteLine(res);
bool res10 = masterList.All(m => m.Menpai == "丐帮");
Console.WriteLine(res);
//显示信息
foreach (var item in res8)
{
Console.WriteLine(item.ToString());
}
}
static bool Test(MartialArtsMaster master)
{
if (master.Level > 8) return true;
return false;
}
反射和特性
Type位于System.Reflection命名空间下
Assembly类在System.Reflection命名空间中定义,它允许访问给定程序集的元数据,它也包含了可以加载和执行程序集。
//每一个类对应一个type对象,这个type对象存储了这个类 有哪些方法跟哪些数据 哪些成员
MyClass my = new MyClass();//一个类中的数据 是存储在对象中的, 但是type对象只存储类的成员
Type type = my.GetType();//通过对象获取这个对象所属类 的Type对象
Console.WriteLine(type.Name);//获取类的名字
Console.WriteLine(type.Namespace);//获取所在的命名空间
Console.WriteLine(type.Assembly);//返回程序集
FieldInfo[] array= type.GetFields();//只能获取public 字段
foreach (FieldInfo info in array)
{
Console.Write(info.Name+" ");
}
PropertyInfo[] array2 = type.GetProperties();//获取属性
foreach (PropertyInfo info in array2)
{
Console.Write(info.Name+" ");
}
MethodInfo[] array3 = type.GetMethods();//获取方法
foreach (MethodInfo info in array3)
{
Console.Write(info.Name+" ");
}
//通过type对象可以获取它对应的类的所有成员(public)
MyClass my = new MyClass();
Assembly assem = my.GetType().Assembly;//通过类的type对象获取它所在的程序集 Assembly
Console.WriteLine(assem.FullName);
Type[] types = assem.GetTypes();
foreach (var type in types)//遍历程序集中定义的类型
{
Console.WriteLine(type);
}
Console.ReadKey();
特性
特性(attribute)是一种允许我们向程序的程序集增加元数据的语言结构。它是用于保存程序结构信息的某种特殊类型的类。
- 将应用了特性的程序结构叫做目标
- 设计用来获取和使用元数据的程序(对象浏览器)叫做特性的消费者
- NET预定了很多特性,我们也可以声明自定义特性
- Obsolete特性
使用Obsolete特性将程序结构标注为过期的,并且在代码编译时,显示有用的警告信息
[Obsolete("这个方法过时了,使用NewMethod代替")] //obsolete特性用来表示一个方法被弃用了
static void OldMethod()
{
Console.WriteLine("Oldmethod");
}
static void NewMethod()
{
}
- Conditional特性
Conditional特性允许我们包括或取消特定方法的所有调用。为方法声明应用Conditional特性并把编译符作为参数来使用。
#define DoTrace //如果不定义这个宏,就不会调用方法TraceMessage
class Program{
[Conditional("DoTrace")] //其中的字符任写
static void TraceMessage(string str){
Console.WriteLine(str);
}
static void Main(){
TraceMessage("Start of Main");
Console.WriteLine("Doing work in Main.")
TraceMessage("End of Main");
}
}
还有一些特性和自定义特性,用的地方太少,等需要的时候再学习。
线程
只有一个前台线程在运行,应用程序的进程就在运行,如果多个前台线程在运行,但是Main方法结束了,应用程序的进程仍然是运行的,直到所有的前台线程完成其任务为止。
在默认情况下,用Thread类创建的线程是前台线程。线程池中的线程总是后台线程。
在用Thread类创建线程的时候,可以设置IsBackground属性,表示它是一个前台线程还是一个后台线程。
当所有的前台线程运行完毕,如果还有后台线程运行的话,所有的后台线程会被终止掉。
委托创建线程
//一般我们会为比较耗时的操作 开启单独的线程去执行,比如下载操作
static int Test(int i, string str)
{
Console.WriteLine("测试线程" + i + str);
Thread.Sleep(100);//让当亲线程休眠(暂停线程的执行) 单位ms
return 100;
}
static void Main(string[] args)
{ //在main线程中执行 一个线程里面语句的执行 是从上到下的
//1,通过委托 开启一个线程
Func<int, string, int> a = Test;//赋值一个委托函数
IAsyncResult xiancheng1 = a.BeginInvoke(100, "循环检测", null, null);// 开启一个新的线程去执行 a所引用的方法
//IAsyncResult 可以取得当前线程的状态
//可以认为线程是同时执行的(异步执行)
Console.WriteLine("main");
while (xiancheng1.IsCompleted == false)//如果当前线程没有执行完毕
{
Console.Write(".");
Thread.Sleep(10); //控制子线程的检测频率
}
int res1 = a.EndInvoke(xiancheng1);//取得异步线程的返回值
Console.WriteLine(res1);
//检测线程结束
IAsyncResult xiancheng2 = a.BeginInvoke(100, "等待方式检测", null, null);
bool isend = xiancheng2.AsyncWaitHandle.WaitOne(1000);// 1000毫秒表示超时时间,如果等待了1000毫秒 线程还没有结束的话 那么这个方法会返回false
//如果在1000毫秒以内线程结束了,那么这个方法会返回true
if (isend)
{
int res2 = a.EndInvoke(xiancheng2);
Console.WriteLine(res2);
}
//通过回调 检测线程结束
//倒数第二个参数是一个委托类型的参数,表示回调函数,就是当线程结束的时候会调用这个委托指向的方法
//倒数第一个参数用来给回调函数传递数据
a.BeginInvoke(100, "回调检测", OnCallBack, a);
a.BeginInvoke(100, "回调匿名检测", xiancheng3 =>
{
int res4 = a.EndInvoke(xiancheng3);//匿名函数可以直接访问外部变量
Console.WriteLine(res4);
}, null);
Console.ReadKey();
//定义的回调函数
static void OnCallBack(IAsyncResult ar)//回调的参数固定IAsyncResult
{
Func<int, string, int> a = ar.AsyncState as Func<int, string, int>;//里氏转换
int res3 = a.EndInvoke(ar);
Console.WriteLine(res3);
}
Thread创建线程
static void DownloadFile(object filename)
{
//Thread.CurrentThread.ManagedThreadId获取当前线程的ID
Console.WriteLine("开始下载:" + Thread.CurrentThread.ManagedThreadId + filename);
Thread.Sleep(2000);
Console.WriteLine("下载完成");
}
static void Main(string[] args)
{
Thread t = new Thread(DownloadFile);
t.IsBackground = true;//设置为后台线程
t.Start("xxx");
Console.WriteLine("主线程");
t.Join(); //当前线程睡眠,等待t线程执行完,然后继续运行下面的代码
Console.ReadKey();
MyThread my = new MyThread("xxx.bt","http://www.xxx.bbs");
Thread t1 = new Thread(my.DownFile);//我们构造一个thread对象的时候,可以传递一个静态方法,也可以传递一个对象的普通方法
t1.Start();
t1.Abort();//终止这个线程的执行
}
线程池
//开启一个工作线程,参数一为函数,后面的参数是传入函数的参数
ThreadPool.QueueUserWorkItem(DownloadFile,"xxx");
任务
Task t = new Task(DownloadFile,"xxx");//创建任务
t.Start();
TaskFactory tf = new TaskFactory(); //创建任务工厂
Task t1 = tf.StartNew(DownloadFile,"xxxx");
连续任务
static void DoFirst()
{
Console.WriteLine("do in task : " + Task.CurrentId);
Thread.Sleep(3000);
}
static void DoSecond(Task t)
{
Console.WriteLine("task " + t.Id + " finished.");
Console.WriteLine("this task id is " + Task.CurrentId);
Thread.Sleep(3000);
}
Task t1 = new Task(DoFirst);
Task t2 = t1.ContinueWith(DoSecond);
Task t3 = t1.ContinueWith(DoSecond);
Task t4 = t2.ContinueWith(DoSecond);
t1.Start();
任务层次结构
我们在一个任务中启动一个新的任务,相当于新的任务是当前任务的子任务,两个任务异步执行,如果父任务执行完了但是子任务没有执行完,它的状态会设置为WaitingForChildrenToComplete,只有子任务也执行完了,父任务的状态就变成RunToCompletion
static void ParentTask()
{
Console.WriteLine("task id " + Task.CurrentId);
var child = new Task(ChildTask);
child.Start();
Thread.Sleep(1000);
Console.WriteLine("parent started child , parent end");
}
static void ChildTask()
{
Console.WriteLine("child");
Thread.Sleep(5000);
Console.WriteLine("child finished ");
}
var parent = new Task(ParentTask);
parent.Start();
Thread.Sleep(2000);
Console.WriteLine(parent.Status);
Thread.Sleep(4000);
Console.WriteLine(parent.Status);
Console.ReadKey();
锁
锁是用来锁住对象的,被锁住的对象只有在当前线程解开后,才能被其他线程访问该对象
static void RaceCondition(object o ){
StateObject state = o as StateObject;
int i = 0;
while(true){
lock(state){ //锁住state对象
state.ChangeState(i++);
}
}
}