委托、匿名方法、Lambda表达式、泛型委托(自定义、Func、Action、Predicate)、约束泛型类和方法、多窗体传递消息、事件、异步编程、二次控件开发

放肆的年华 提交于 2020-01-02 07:13:31

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         }
Lambda表达式

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     }
泛型委托2

 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         } 
Func委托的基本使用

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         }
Predicate委托应用

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     }
default关键字

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     }
dynamic关键字在泛型类中的使用
 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
 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         }
从窗体2

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         }
窗体应用

 

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!