1.匿名方法
没有具体名称,只有委托关键字、方法参数、方法体,所以称之为匿名方法
匿名方法允许将代码块(方法体部分)通过委托变量作为参数传递,以代替独立定义的方法
总结:
方法体要以delegate开头,其后是参数列表,后面紧跟花括号编写方法体,最后以分号结尾
匿名方法是将方法定义与委托变量两个步骤合在一起,省略了方法的单独定义
如果一个方法有一个委托类型的参数,可以直接将匿名方法作为实参。

1 //声明委托
2 public delegate int MyDelegate(int a, int b);
3
4 static void Main(string[] args)
5 {//匿名方法
6 MyDelegate objDel = delegate (int a, int b)
7 {
8 return a + b;
9 };
10 Console.WriteLine(objDel(10, 20));
11 Console.ReadLine();
12 }
2.lambda表达式
C#3.0引入lambda表达式,lambda表达式是匿名方法更简介使用的一种方式
(参数列表) => {方法体} =>读作goes to
lambda表达式参数列表中的参数类型可以是“明确”类型或者是“推断类型”(可以省略参数类型)
如果是推断类型,参数数据类型将由编译器根据上下文自动推断出来
一般情况下还是写参数类型的好,方便自己和他人理解
如果参数只有一个可以省略();如果方法体只有一行代码可以省略{}
3.lambda表达式总结
两种方式:(input args)=>表达式 (input args)=>{语句1;语句2;......}
举例1:只有一个参数的时候,括号可选 Func<int,bool> del1=(x)=>{return x>0;};
举例2:可简化为 Func<int,bool> del2=x=>x>0;
举例3:两个或更多输入参数由逗号分隔 Func<int,int,bool> del3=(x,y)=>x==y;
举例4:没有参数时,直接输入一个空的括号 Action del4=()=>{...}

1 //声明委托
2 public delegate int MyDelegate(int a, int b);
3 static void Main(string[] args)
4 {
5 //一条语句未省略{}
6 MyDelegate objDel0 = (int a, int b) => { return a + b; };
7 //一条语句省略{}
8 MyDelegate objDel1 = (int a, int b) => a + b;
9 Console.WriteLine(objDel0(10, 20));
10 Console.WriteLine(objDel1(10, 20));
11 Console.ReadLine();
12 }
4.lambda与匿名方法比较
Lambda表达式本身就是匿名方法
Lambda表达式的参数可以允许不指明参数类型,而匿名方法的参数必须明确指明参数类型
Lambda表达式方法体允许由单一表达式或多条语句组成,而匿名方法不允许单一表达式形式
5.自定义泛型委托
当一类相同方法类似,但方法的参数类型不一致的时候可以考虑使用泛型委托
因为是泛型,所以在定义委托时用T表示参数类型,在定义委托变量时再指定方法类型

1 //1.定义泛型委托
2 public delegate T MyDele<T>(T obj1, T obj2);
3 class Program
4 {
5 //2.定义委托方法
6 static int Add(int a, int b) => a + b;
7 static double Sub(double a, double b) => a - b;
8 static void Main(string[] args)
9 {
10 //3.定义委托变量
11 MyDele<int> objIntDele = Add;
12 MyDele<double> objDouDele = Sub;
13 //4.使用委托变量
14 Console.WriteLine(objIntDele(10, 20));
15 Console.WriteLine(objDouDele(2.2, 5.7));
16 Console.ReadLine();//使用新特性 using static System.Console;
17 }
18 }

1 //定义泛型委托
2 public delegate T MyGenericDeleage<T>(T obj1, T obj2);
3 class Program
4 {
5 static int Add(int a, int b)
6 {
7 return a + b;
8 }
9 static double Sub(double a, double b)
10 {
11 return a - b;
12 }
13
14 //泛型委托:匿名方法、Lambda表达式
15 static void Main(string[] args)
16 {
17 //【1】使用委托
18 MyGenericDeleage<int> objDelegate1 = Add;
19 MyGenericDeleage<double > objDelegate2 = Sub;
20
21 Console.WriteLine(objDelegate1(10,20));
22 Console.WriteLine(objDelegate2(10, 20));
23 Console.WriteLine("-----------------");
24
25 //【2】使用匿名方法
26 MyGenericDeleage<int> objDelegate3 = delegate(int a, int b) { return a + b; };
27 MyGenericDeleage<double > objDelegate4 = delegate(double a, double b) { return a - b; };
28
29 Console.WriteLine(objDelegate3(10, 20));
30 Console.WriteLine(objDelegate4(10, 20));
31 Console.WriteLine("-----------------");
32
33 //【3】使用Lambda表达式
34 MyGenericDeleage<int> objDelegate5 = (a, b) => a + b;
35 MyGenericDeleage<double> objDelegate6 = (a, b) => a - b;
36
37 Console.WriteLine(objDelegate5(10, 20));
38 Console.WriteLine(objDelegate6(10, 20));
39 Console.ReadLine();
40 }
41 }
6.Func<T>委托 :最后一个参数为返回值类型
Func<>委托是微软自定义好的泛型委托
Func委托声明的最后一个泛型类型是委托所接受方法的返回值类型

1 static double Add(int a, int b)
2 {
3 return a + b;
4 }
5 static void Main(string[] args)
6 {
7 Func<int, int, double> func0 = Add;
8 double result = func0(10, 20);
9 //使用Lambda表达式
10 Func<int, int, double> func1 = (a, b) => a + b;
11 Console.WriteLine(func0(10, 20));
12 Console.WriteLine(func1(10, 20));
13 Console.ReadLine();
14 }
7.编写一个方法,从数组中指定位置抽取3个数,求和、求积 int[] nums={10,9,8,7,6,5,4,3,2};

1 static void Main(string[] args)
2 {
3 int[] nums = { 10, 9, 8, 7, 6, 5, 4, 3, 2 };
4 Console.WriteLine("------不使用委托-------");
5 Console.WriteLine(GetAdd(nums, 0, 3));
6 Console.WriteLine(GetMulti(nums, 0, 3));
7 Console.WriteLine("------使用Func委托-------");
8 Console.WriteLine(CommmonCalcu(Add, nums, 0, 3));
9 Console.WriteLine(CommmonCalcu(Multi, nums, 0, 3));
10 Console.WriteLine("------使用Func委托+Lambda表达式-------");
11 Console.WriteLine(CommmonCalcu((int a, int b) => a + b, nums, 0, 3));
12 Console.WriteLine(CommmonCalcu((int a, int b) => a * b, nums, 0, 3));
13 Console.ReadLine();
14 }
15
16 static int CommmonCalcu(Func<int,int,int> openation,int[] nums,int from,int to)
17 {
18 int result = nums[from]; //无论加乘,都需要使用第一个元素
19 for (int i = from+1; i <= to; i++)
20 {
21 result = openation(result, nums[i]);
22 }
23 return result;
24 }
25
26 static int Add(int a, int b)
27 {
28 return a + b;
29 }
30
31 static int Multi(int a, int b)
32 {
33 return a * b;
34 }
35
36 static int GetAdd(int[] nums, int from, int to)
37 {
38 int result = 0;
39 for (int i = from; i <= to; i++)
40 {
41 result += nums[i];
42 }
43 return result;
44 }
45
46 static int GetMulti(int[] nums, int from, int to)
47 {
48 int result = 1;
49 for (int i = from; i <= to; i++)
50 {
51 result *= nums[i];
52 }
53 return result;
54 }
Func委托引用一个有返回值的方法,也就是将方法作为另一个方法的“参数”
8.Action委托
Func委托必须要求接受的方法有一个返回值
Action委托接受一个没有返回值的方法,返回值为void
应用:在跨线程访问可视化控件的时候经常使用Action委托
9.Predicate委托
Predicate<T>委托定义如下:
public delegate bool Predicate<T>(T obj);
Predicate<T>委托变量引用一个“判断条件函数”,条件满足返回true。

1 static void Main(string[] args)
2 {
3 List<Student> ListAll = new List<Student>()
4 {
5 new Student(){stuID=10001,stuName="小杨"},
6 new Student(){stuID=10002,stuName="小朱"},
7 new Student(){stuID=10003,stuName="小王"},
8 new Student(){stuID=10004,stuName="小李"},
9 new Student(){stuID=10005,stuName="小刘"},
10 new Student(){stuID=10006,stuName="小张"},
11 new Student(){stuID=10007,stuName="小梅"}
12 };
13 //List<T>集合中定义了一个FindAll方法:public T FindAll(Predicate<T> match)
14 List<Student> list = ListAll.FindAll(s => s.stuID > 10003);
15 foreach (var item in list)
16 {
17 Console.WriteLine(item.stuName + ":" + item.stuID);
18 }
19 Console.ReadLine();
20 }
10.FindAll方法与Linq语句与Linq方法查询比较

1 static void Main(string[] args)
2 {
3 List<Student> ListAll = new List<Student>()
4 {
5 new Student(){stuID=10001,stuName="小杨"},
6 new Student(){stuID=10002,stuName="小朱"},
7 new Student(){stuID=10003,stuName="小王"},
8 new Student(){stuID=10004,stuName="小李"},
9 new Student(){stuID=10005,stuName="小刘"},
10 new Student(){stuID=10006,stuName="小张"},
11 new Student(){stuID=10007,stuName="小梅"}
12 };
13 //List<T>集合中定义了一个FindAll方法:public T FindAll(Predicate<T> match)
14 List<Student> list0 = ListAll.FindAll(s => s.stuID > 10003);
15 Console.WriteLine("----------使用Predicate委托----------");
16 foreach (var item in list0)
17 {
18 Console.WriteLine(item.stuName + ":" + item.stuID);
19 }
20 Console.WriteLine("----------使用Linq语句查询----------");
21 var list1 = from stu in ListAll
22 where stu.stuID > 10003
23 select stu;
24 foreach (var item in list1)
25 {
26 Console.WriteLine(item.stuName + ":" + item.stuID);
27 }
28 Console.WriteLine("----------使用Linq方法查询----------");
29 var list2 = ListAll.Where(s => s.stuID > 10003)
30 .Select(s => s);
31 foreach (var item in list2)
32 {
33 Console.WriteLine(item.stuName + ":" + item.stuID);
34 }
35 Console.ReadLine();
36 }
11.泛型再结
泛型好处:类型安全、方便编码、无需拆装箱操作
常见泛型:泛型类和泛型方法
后续深入:泛型委托(自定义泛型委托、Func、Action、Predicate)
提取不变的,封装变化的
12.泛型类的规范 public class 类名<T>{类的成员...}
T:仅仅表示一个占位符,只要符合C#的命名规范即可使用,但一般都是用T
T:表示一个通用的数据类型,在使用的时候用实际类型代替
T:泛型类可以在定义中包含多个任意类型的参数,参数之间用多个逗号分隔开
例如 class MyGenericClass<T1,T2,T3>{...}
各种类型参数可以用作成员变量的类型、属性或方法等成员的返回类型已经方法的参数类型等。
13.泛型应用于出入栈

1 /// <summary>
2 /// 编写一个入栈和出栈操作的通用类
3 /// </summary>
4 /// <typeparam name="T">可以是任意类型</typeparam>
5 public class MyStack<T>
6 {
7 private T[] stack;
8 private int size;//栈数据容量
9 private int stackPoint;//当前位置指针
10
11 public MyStack(int size)
12 {
13 this.size = size;
14 stack = new T[size];
15 stackPoint = -1;
16 }
17
18 /// <summary>
19 /// 入栈方法
20 /// </summary>
21 /// <param name="item"></param>
22 public void Push(T item)
23 {
24 if (stackPoint >= size)
25 {
26 Console.WriteLine("栈已满");
27 }
28 else
29 {
30 stackPoint++;
31 stack[stackPoint] = item;
32 }
33 }
34 /// <summary>
35 /// 出栈方法
36 /// </summary>
37 /// <returns></returns>
38 public T Pop()
39 {
40 T data = this.stack[stackPoint];
41 stackPoint--;
42 return data;
43 }
44 }

1 //栈:先进后出
2 static void Main(string[] args)
3 {
4 MyStack<int> objStack = new MyStack<int>(5);
5 objStack.Push(1);
6 objStack.Push(2);
7 objStack.Push(3);
8 objStack.Push(4);
9 objStack.Push(5);
10 Console.WriteLine(objStack.Pop());
11 Console.WriteLine(objStack.Pop());
12 Console.WriteLine(objStack.Pop());
13 Console.WriteLine(objStack.Pop());
14 Console.WriteLine(objStack.Pop());
15 Console.ReadLine();
16 }
14.default关键字在泛型类中的使用

1 class MyGenericClass1<T1, T2>
2 {
3 private T1 obj1;
4
5 private MyGenericClass1()
6 {
7 //obj1 = null; //不能这么用
8 //obj1 = new T1();//不能随便假设某种类型,这种类型也许没有构造方法,也许是私有的。
9
10 //解决方法:default关键字
11 obj1 = default(T1);//如果T1是引用类型,就赋值null,如果是值类型就给默认值,对于数值类型就是0,结构类型的话要依据具体的成员类型确定为0或者null
12 }
13 }
15.添加带约束的泛型类
约束泛型类:泛型类的参数类型受约束,例如泛型类有三个泛型参数,第一个要求必须是值类型、第二个要求必须是引用类型,诸如此类的约束。

1 class MyGenericCalss2<T1, T2, T3>
2 where T1 : struct //说明:类型必须是值类型
3 where T2 : class //说明:类型必须是引用类型
4 where T3 : new() //说明:类型必须有一个无参数的构造方法,且必须放到最后
5 //其他类型:基类类型、接口类型
6 {
7 public List<T2> ProductList { get; set; } //产品列表
8 public T3 Publisher { get; set; } //发行者
9 public MyGenericCalss2()
10 {
11 ProductList = new List<T2>();
12 Publisher = new T3();
13 }
14 /// <summary>
15 /// 购买第几个产品
16 /// </summary>
17 /// <param name="num">产品索引</param>
18 /// <returns>购买的产品</returns>
19 public T2 Buy(T1 num)
20 {
21 // return ProductList[num];//直接写是错误的。因为数组通过下标访问的时候必须是int类型,而int和T1又是冲突的
22 dynamic a = num; //动态类型,在编译时解析
23 return ProductList[a];
24 }
25 }

1 /// <summary>
2 /// 课程(产品类)
3 /// </summary>
4 class Course
5 {
6 /// <summary>
7 /// 课程名称
8 /// </summary>
9 public string CourseName { get; set; }
10 /// <summary>
11 /// 学习周期
12 /// </summary>
13 public int Period { get; set; }
14 }
15 /// <summary>
16 /// 课程老师(发行人)
17 /// </summary>
18 class Teacher
19 {
20 public string Name { get; set; }//姓名
21 public int Count { get; set; }//授课数量
22 }

1 static void Main(string[] args)
2 {
3 //【1】实例化泛型类型对象
4 MyGenericCalss2<int, Course, Teacher> myClass2 = new MyGenericCalss2<int, Course, Teacher>();
5 //【2】给对象属性赋值
6 myClass2.Publisher = new Teacher() { Name = "常老师", Count = 20 }; //课程的发行人
7 myClass2.ProductList = new List<Course>() //课程(产品)列表
8 {
9 new Course(){CourseName =".NET-CS+BS高级工程师VIP班",Period=6},
10 new Course(){CourseName =".NET-CS高级工程师VIP班",Period=3},
11 new Course(){CourseName =".NET-BS高级工程师VIP班",Period=3},
12 };
13 //【3】调用对象方法
14 Course myCourse = myClass2.Buy(0);
15 //数据处理
16 string info = string.Format("我购买的课程是:{0} 学期:{1}个月 课程主讲:{2}",
17 myCourse.CourseName,
18 myCourse.Period,
19 myClass2.Publisher.Name);
20 Console.WriteLine(info);
21 Console.ReadLine();
22 }

1 /// <summary>
2 /// 自己写的泛型约束类,模拟一个商品列表,购买以及商品发行人的实例
3 /// </summary>
4 class Program
5 {
6 static void Main(string[] args)
7 {
8 MyGenericClass<int, Course, Teacher> objGeneric = new MyGenericClass<int, Course, Teacher>();
9 objGeneric.Publisher = new Teacher() { TeaName = "杨老师" };
10 objGeneric.Products = new List<Course>()
11 {
12 new Course(){CourseName="C#教程",Period=12},
13 new Course(){CourseName="VB教程",Period=10},
14 new Course(){CourseName="SQLServer教程",Period=6}
15 };
16 Course objCourseBuy = objGeneric.Buy(1);
17 string info = string.Format("购买的课程是{0},课程授课时长是{1},课程主讲老师是{2}",
18 objCourseBuy.CourseName, objCourseBuy.Period, objGeneric.Publisher.TeaName);
19 Console.WriteLine(info);
20 Console.ReadLine();
21 }
22 }
23
24 /// <summary>
25 /// 商品交互委托泛型类
26 /// </summary>
27 /// <typeparam name="T1">商品索引</typeparam>
28 /// <typeparam name="T2">商品列表</typeparam>
29 /// <typeparam name="T3">商品发行人</typeparam>
30 public class MyGenericClass<T1, T2, T3>
31 where T1 : struct //T1必须是值类型(值类型包括整型、浮点型、decimal、bool、enum)
32 where T2 : class //T2必须是引用类型(引用类型包括数组、class、interface、delegate、object、string)
33 where T3 : new() //T3必须有一个空的构造函数
34 {
35 public T3 Publisher; //发行人
36 public List<T2> Products = new List<T2>(); //商品
37 public T2 Buy(T1 index)
38 {
39 dynamic t1 = index;
40 return Products[t1];
41 }
42 }
43
44 /// <summary>
45 /// 课程(商品)类
46 /// </summary>
47 public class Course
48 {
49 /// <summary>
50 /// 课程名称
51 /// </summary>
52 public string CourseName { get; set; }
53 /// <summary>
54 /// 课程周期
55 /// </summary>
56 public int Period { get; set; }
57 }
58
59 /// <summary>
60 /// 老师(发行人)类
61 /// </summary>
62 public class Teacher
63 {
64 /// <summary>
65 /// 老师姓名
66 /// </summary>
67 public string TeaName { get; set; }
68 }
16.泛型方法

1 class Program
2 {
3 static void Main(string[] args)
4 {
5 Console.WriteLine(Add1("大家好", "我是帅气的杨三少"));
6 Console.WriteLine("10+20={0}", Add1(10, 20));
7 Console.WriteLine("10.2+20.3={0}", Add1(10.2, 20.3));
8 Console.WriteLine("10+20.6={0}", Add1(10, 20.6));
9 Console.ReadLine();
10 }
11
12 static T Add1<T>(T a, T b)
13 {
14 dynamic a1 = a;
15 dynamic b1 = b;
16 return a1 + b1;
17 }
18
19 static T Add2<T>(T a, T b) where T : struct
20 {
21 dynamic a1 = a;
22 dynamic b1 = b;
23 return a1 + b1;
24 }
25 }
17.使用委托从窗体向子窗体发送消息

//1.在主窗体定义委托
public delegate void CountDele(string str);
public partial class FrmMain : Form
{
public FrmMain()
{
InitializeComponent();
FrmOther objOther = new FrmOther();
//4.将委托变量与方法关联
objOther.objCountDele = ShowCount;
objOther.Show();
}
//2.在主窗体定义委托方法
private void ShowCount(string str)
{
lbl_Count.Text = str;
}
}

1 //3.定义委托变量
2 public CountDele objCountDele;
3 private int count = 0;
4 public FrmOther()
5 {
6 InitializeComponent();
7 }
8
9 private void btn_1_Click(object sender, EventArgs e)
10 {
11 count++;
12 //5.委托代替方法执行
13 objCountDele(count.ToString());
14 }
18.使用委托主窗体向多个从窗体传递消息

1 //1.定义委托
2 public delegate void DeleCount(string str);
3 public partial class FrmMain : Form
4 {
5 //3.定义委托变量
6 private DeleCount objDeleCount;
7 private int count = 0;
8 public FrmMain()
9 {
10 InitializeComponent();
11
12 FrmOther01 frm01 = new FrmOther01();
13 FrmOther02 frm02 = new FrmOther02();
14 FrmOther03 frm03 = new FrmOther03();
15 //4.委托变量关联委托方法
16 objDeleCount += frm01.ShowCount;
17 objDeleCount += frm02.ShowCount;
18 objDeleCount += frm03.ShowCount;
19 frm01.Show();
20 frm02.Show();
21 frm03.Show();
22 }
23
24 private void btn_Add_Click(object sender, EventArgs e)
25 {
26 //5.调用委托变量传递消息
27 count++;
28 objDeleCount(count.ToString());
29 }
30
31 private void btn_Clear_Click(object sender, EventArgs e)
32 {
33 //5.调用委托变量传递消息
34 count = 0;
35 objDeleCount(count.ToString());
36 }
37 }

1 //2.定义委托方法
2 public void ShowCount(string str)
3 {
4 lbl_Count.Text = str;
5 }
19.事件event
事件:事件是对象在外界“刺激”下发生事情,而对外提供的一种消息机制。
事件就是委托类型。
事件的两个参与者:
发送者(Sender):即对象本身,当本身状态发生变化时触发事件,并通知事件的接收者。
接收者(Receiver):用来处理事件的(事件的关注者),在事件发送者触发一个事件后,会自动执行的内容。
事件一般的使用规则:委托声明在主窗体类内。委托对象也叫委托实例或委托变量或事件event定义在事件的发送者所在类中,委托调用的方法定义在事件的接收者所在类中,事件关联在主窗体内,事件代替方法实现调用在发送者所在类内。
20.主窗体统一向多个从窗体发送消息(类似广播),与委托类似

1 //1.声明委托
2 public delegate void DeleSendMsg(string msg);
3 public partial class FrmMain : Form
4 {
5 //3.定义事件
6 public event DeleSendMsg EventSendMsg;
7 public FrmMain()
8 {
9 InitializeComponent();
10 FrmClient01 frm1 = new FrmClient01();
11 FrmClient02 frm2 = new FrmClient02();
12 //4.将主窗体的事件与客户端窗体的接收方法关联起来
13 EventSendMsg += frm1.Receive;
14 EventSendMsg += frm2.Receive;
15 frm1.Show();
16 frm2.Show();
17 }
18
19 private void btn_SendMsg_Click(object sender, EventArgs e)
20 {
21 //5.使用事件发送消息
22 EventSendMsg(tb_Msg.Text.Trim());
23 }
24 }

1 //2.定义客户端窗体的接收方法
2 public void Receive(string msg)
3 {
4 tb_Msg.Text = msg;
5 }
21.从窗体向主窗体发送消息,要求在主窗体中显示是来自谁的消息

1 //1.定义委托
2 public delegate void DeleSendMsg(string msg);
3 public partial class FrmMain : Form
4 {
5 public FrmMain()
6 {
7 InitializeComponent();
8 FrmClient1 frm1 = new FrmClient1();
9 FrmClient2 frm2 = new FrmClient2();
10 //5.事件关联方法
11 frm1.EventSendMsg += Receice;
12 frm2.EventSendMsg += Receice;
13 frm1.Show();
14 frm2.Show();
15 }
16
17 //2.定义主窗体接收消息的方法
18 private void Receice(string msg)
19 {
20 tb_Msg.Text += msg + "\r\n";
21 }
22
23 private void btn_ClearMsg_Click(object sender, EventArgs e)
24 {
25 tb_Msg.Text = "";
26 }
27 }

1 //3.定义事件
2 public event DeleSendMsg EventSendMsg;
3 public FrmClient1()
4 {
5 InitializeComponent();
6 }
7
8 private void btn_SendMsg_Click(object sender, EventArgs e)
9 {
10 //4.事件发送消息
11 EventSendMsg("客户端1的消息:" + tb_Msg.Text.Trim());
12 }

1 //3.定义事件
2 public event DeleSendMsg EventSendMsg;
3 public FrmClient2()
4 {
5 InitializeComponent();
6 }
7
8 private void btn_SendMsg_Click(object sender, EventArgs e)
9 {
10 //4.事件发送消息
11 EventSendMsg("客户端2的消息:" + tb_Msg.Text.Trim());
12 }
22.委托与事件的比较
事件在内部使用可以用“=”,如果是外部使用事件对象必须放在“+=”或“-=”的左边。
相同点:事件对象本质就是一个私有的委托对象,以及公有的两个方法,add和remove。
不同点:+=方式,实际上是调用add方法对委托对象进行添加。
事件对象私有化后,无法直接从外部赋值(内部赋值除外)。例如:事件=null;会出现编译错误,而委托允许这样做。
好处:避免用户直接将对象清除。比如微软给开发者所定义的各种事件,只允许开发者通过+=方式使用,而不允许开发者把定义好的事件清除掉。Click=null;这是不允许的。只能通过-=方式断开事件,这样能起到保护作用,而委托“太开放”
23.异步编程
异步编程:核心是基于委托实现的。
委托类型的BeginInvoke(<输入和输出变量>,AsyncCallBack callBack,object ayncState)方法是异步调用的核心
第一个参数10,表示委托对应的方法实参
第二个参数CallBack,回调函数,表示异步调用结束后,自动调用的方法
第三个参数AsyncState,用于向回调函数提供相应的参数信息
返回值:IAsyncResult异步操作状态接口,封装了异步执行的参数
委托类型的EndInvoke(IAsyncResult)方法
参数是BeginInvoke方法的返回值
返回值:异步执行的结果,返回值类型和委托类型、委托方法的返回值类型一致

1 //异步编程的核心是基于委托
2 public partial class FrmMain : Form
3 {
4 //异步执行【1】.声明委托
5 public delegate int DeleExecute(int a);
6 public FrmMain()
7 {
8 InitializeComponent();
9 }
10
11 //同步执行
12 private void btnTest1_Click(object sender, EventArgs e)
13 {
14 lblInfo1.Text = ExecuteTask1(30).ToString();
15 lblInfo2.Text = ExecuteTask2(40).ToString();
16 }
17
18 //异步执行【3】.异步调用
19 private void btnTest2_Click(object sender, EventArgs e)
20 {
21 //定义委托变量,引用相应方法
22 DeleExecute objDeleExecute = new DeleExecute(ExecuteTask1);
23
24 //通过委托异步调用方法ExecuteTask1
25 //委托类型的BeginInvoke(<输入和输出变量>,AsyncCallBack callBack,object ayncState)方法是异步调用的核心
26 //第一个参数10,表示委托对应的方法实参
27 //第二个参数CallBack,回调函数,表示异步调用结束后,自动调用的方法
28 //第三个参数AsyncState,用于向回调函数提供相应的参数信息
29 //返回值:IAsyncResult异步操作状态接口,封装了异步执行的参数
30
31 //【1】.异步调用任务
32 IAsyncResult result = objDeleExecute.BeginInvoke(50, null, null);
33 lblInfo1.Text = "异步执行开始计算...";
34 //【2】.可以并行执行其他任务
35 lblInfo2.Text = ExecuteTask2(60).ToString();
36 //【3】.获取异步执行的结果
37 //委托类型的EndInvoke(IAsyncResult)方法
38 //参数是BeginInvoke方法的返回值
39 //返回值:异步执行的结果,返回值类型和委托类型、委托方法的返回值类型一致
40 int r = objDeleExecute.EndInvoke(result);
41 lblInfo1.Text = r.ToString();
42 }
43
44 //异步编程【2】.定义委托方法
45 private int ExecuteTask1(int a)
46 {
47 System.Threading.Thread.Sleep(5000);
48 return a * a;
49 }
50
51 private int ExecuteTask2(int a)
52 {
53 return a * a;
54 }
55 }

1 //同时执行10个任务,第i个任务演示i秒,计算返回i的平方
2 namespace _016异步编程执行多个任务
3 {
4 //【1】.声明委托
5 public delegate int DeleExecuteTasks(int a,int ms);
6 public partial class FrmMain : Form
7 {
8 //【3】.创建委托变量,因为异步函数和回调函数都要用,所以定义为成员变量
9 private DeleExecuteTasks objDeleExecuteTasks;
10 public FrmMain()
11 {
12 InitializeComponent();
13 //【3】.初始化委托变量
14 objDeleExecuteTasks = new DeleExecuteTasks(ExecuteTask);
15 }
16
17 //【2】.定义委托方法
18 private int ExecuteTask(int a, int ms)
19 {
20 System.Threading.Thread.Sleep(ms);
21 return a * a;
22 }
23 //【4】.异步同时执行多个任务
24 private void btn_AsyncTasks_Click(object sender, EventArgs e)
25 {
26 //使用循环发布多个任务
27 for (int i = 1; i < 11; i++)
28 {
29 //开始异步执行
30 //前两个参数与异步方法内的参数一致
31 //AsyncCallBack:回调函数
32 //object @object:最后一个参数是给回调函数的字段AsyncState(IAsyncResult.AsyncState)赋值,如果参数很多可以定义成类或结构
33 objDeleExecuteTasks.BeginInvoke(10 * i, 1000 * i, MyAsyncCallBack, i);
34 }
35 }
36
37 //【5】.回调函数:作用是当任务完成后的反馈机制,回调函数可以有自己的自定义参数
38 private void MyAsyncCallBack(IAsyncResult result)
39 {
40 int r = objDeleExecuteTasks.EndInvoke(result);
41 //IAsyncResult.AsyncState用来封装回调函数自定义参数,是object类型
42 Console.WriteLine("第{0}个任务的执行结果为:{1}", result.AsyncState, r);
43 }
44 }
45 }
24.异步编程总结
异步编程是建立在委托基础上一种编程的方法
异步调用的每个方法都是在独立的线程中执行,本质上异步编程就是一种多线程程序,是简化的多线程
比较适合在后台运行较为耗时的简单任务,并且任务之间要求相互独立,任务中不应该有直接访问可视化控件的代码
如果后台任务要求必须按照特定顺序执行,或者访问共享资源,则异步编程不太合适,应该选择多线程开发技术
25.线程Thread
进程:一个正在运行的程序就是一个进程,操作系统根据进程分配各种资源(比入内存...)
线程:操作系统为了提高效率会将一个进程分成多个线程,并按照线程来分配CPU执行时间
线程特点:在具有多个CPU的计算机中,可以并行执行
Thread类:表示托管线程,每个Thread对象都代表一个托管线程,每个托管线程都会对应一个函数
ThreadStart 委托定义:public delegate void ThreadStart() 无返回值且无参数

1 private void btn_TaskThread1_Click(object sender, EventArgs e)
2 {
3 //ThreadStart 委托类型 返回值void且无参数
4 int a = 0;
5 Thread objThread1=new Thread(delegate()
6 {
7 for (int i = 1; i <= 10; i++)
8 {
9 a += i;
10 Console.WriteLine("-----1线程------{0}---", a);
11 Thread.Sleep(500);
12 }
13 });
14 objThread1.IsBackground = true;
15 objThread1.Start();
16 }
17
18 private void btn_TaskThread2_Click(object sender, EventArgs e)
19 {
20 Thread objThread2 = new Thread(() =>
21 {
22 for (int i = 1; i < 100; i++)
23 {
24 Console.WriteLine("-----2线程------{0}---", i);
25 Thread.Sleep(20);
26 }
27 });
28 objThread2.IsBackground = true;
29 objThread2.Start();
30 }
26.跨线程访问控件

1 private void btnExecute1_Click(object sender, EventArgs e)
2 {
3 Thread objThread1 = new Thread(() =>
4 {
5 for (int i = 1; i < 11; i++)
6 {
7 if (lblResult1.InvokeRequired)
8 {
9 lblResult1.Invoke(new Action<string>(s => lblResult1.Text = s), (i * i).ToString());
10 Thread.Sleep(100);
11 }
12 }
13 });
14 objThread1.IsBackground = true;
15 objThread1.Start();
16 }
17
18 private void btnExecute2_Click(object sender, EventArgs e)
19 {
20 Thread objThread2 = new Thread(() =>
21 {
22 for (int i = 11; i < 21; i++)
23 {
24 if (lblResult2.InvokeRequired)
25 {
26 lblResult2.Invoke(new Action<string>(s => { lblResult2.Text = s; }), (i * i).ToString());
27 Thread.Sleep(200);
28 }
29 }
30 });
31 objThread2.IsBackground = true;
32 objThread2.Start();
33 }
27.制作二次开发的控件
1.新建项目——>选择类库——>删除自生成的class1——>添加组件——>进入代码视图——>将ComPonent直接替换成TextBox——>引用添加System.Windows.Forms——>using命名空间——>添加一个ErrorProvider——>编写public的验证是否为空的方法

1 /// <summary>
2 /// 判断文本框输入是否为空
3 /// </summary>
4 /// <returns>返回值【0为空】【1不为空】</returns>
5 public int BeginCheckEmpty()
6 {
7 if (this.Text.Trim() == "")
8 {
9 errorProvider.SetError(this, "必填项不能为空!");
10 return 0;
11 }
12 else
13 {
14 errorProvider.SetError(this,string.Empty);
15 return 1;
16 }
17 }

1 /// <summary>
2 /// 判断文本框输入是否为正整数
3 /// </summary>
4 /// <param name="regularExpression">正则表达式</param>
5 /// <param name="errorMsg">匹配失败后返回的消息</param>
6 /// <returns>返回值【0匹配失败】【1匹配成功】</returns>
7 public int BeginCheckRegularExpression(string regularExpression, string errorMsg)
8 {
9 if (BeginCheckEmpty() == 0)
10 {
11 return 0;
12 }
13 Regex objRegex = new Regex(regularExpression, RegexOptions.IgnoreCase);
14 if (objRegex.IsMatch(this.Text.Trim()))
15 {
16 errorProvider.SetError(this, string.Empty);
17 return 1;
18 }
19 else
20 {
21 errorProvider.SetError(this, errorMsg);
22 return 0;
23 }
24 }

1 private void btn_Save_Click(object sender, EventArgs e)
2 {
3 int a = STB_Name.BeginCheckEmpty();
4 int b = STB_Age.BeginCheckRegularExpression(@"^[1-9]\d*$", "年龄必须为正整数!");
5 int result = a * b;
6 if (result!=0)
7 {
8 MessageBox.Show("保存成功");
9 }
10 }
来源:https://www.cnblogs.com/yangmengke2018/p/10939667.html
