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.委托引入

  委托本质:是一个类,继承自System.MulticastDelegate,里面内置了几个方法(Invoke()、BeginInvoke()、EndInvoke())

  委托的声明:public delegate void MyDelete(int num);   细看委托的声明,如果把delegate去掉就是一个方法的声明。

  委托的实例化:实例化委托之前必须写好委托实例传入的方法,这个方法和委托声明必须有相同的返回值和参数。

  委托的调用:Invoke()也可以直接调用。

  委托的三大作用:【1】逻辑解耦,减少重复代码【2】异步多线程【3】多播委托,基于观察者模式

//【1】委托声明
public delegate void NoReturnWithPara(int para);

//【2】委托传入的方法
private void TheMethod(int num)
{
    Console.WriteLine($"我就是那个数{num}");
}

public void Show()
{
    //【3】实例化委托
    NoReturnWithPara noReturnWithPara = new NoReturnWithPara(TheMethod);
    //【4】调用委托实例
    noReturnWithPara.Invoke(22);
    noReturnWithPara(11);
}

//【5】委托:可以把方法当成参数进行传递
委托的声明、实例化、调用
/* 委托解耦的实例说明
 * 背景:一群学生,姓名、年龄、住址各异,要求筛选出特定条件的学生个数。
 * 例如筛选出名字为2个字的学生、年龄大于20的学生、家住昆山的学生、和满足以上所有的学生
 * 最笨的方法(暂不考虑linq),【1】先新建一个list、【2】foreach挨个遍历、【3】判断条件满足、【4】加入list、【5】输出list个数
 * 细分析以上5个步骤:只有步骤3判断条件满足这里不一样,别的四个步骤都一样
 * 四个一样的步骤叫共有逻辑、3判断条件满足叫独有逻辑,解耦解的是这两者之间的耦合关系,在3判断条件满足这里使用委托
 */
public class DelegateTest
    {
        //准备数据
        public List<Student> students = new List<Student>()
        {
            new Student()
            {
                Name="张三",
                Age=36,
                Address="昆山高新区"
            },
            new Student()
            {
                Name="李四平",
                Age=32,
                Address="昆山开发区"
            },
            new Student()
            {
                Name="王麻子",
                Age=18,
                Address="上海青浦区"
            },
            new Student()
            {
                Name="赵六",
                Age=36,
                Address="天津黑芝麻胡同"
            }
        };

        //【1】定义委托
        public delegate bool JudgeDele(Student student);

        //【2】准备判断条件
        public bool JudgeNameEqual2(Student student)
        {
            return student.Name.Length == 2;
        }
        public bool JudgeAgeUp20(Student student)
        {
            return student.Age >= 20;
        }
        public bool JudgeAddressInKun(Student student)
        {
            return student.Address.Contains("昆山");
        }
        public bool JudgeAll(Student student)
        {
            return student.Name.Length == 2 && student.Age >= 20 && student.Address.Contains("昆山");
        }

        //判断逻辑传递进来+实现共用逻辑,委托解耦,减少重复代码
        public int GetStudents(List<Student> students, JudgeDele dele)
        {
            List<Student> listStu = new List<Student>();
            foreach (Student student in students)
            {
                if (dele.Invoke(student))//【4】利用委托代替判断方法
                {
                    listStu.Add(student);
                }
            }
            return listStu.Count();
        }
    }


                //【3】实例化委托
                DelegateTest delegateTest = new DelegateTest();
                int NameEqual2 = delegateTest.GetStudents(delegateTest.students, delegateTest.JudgeNameEqual2);
                int AgeUp20 = delegateTest.GetStudents(delegateTest.students, delegateTest.JudgeAgeUp20);
                int AddressInKun = delegateTest.GetStudents(delegateTest.students, delegateTest.JudgeAddressInKun);
                int JudgeAll = delegateTest.GetStudents(delegateTest.students, delegateTest.JudgeAll);
                Console.WriteLine($"NameEqual2:{NameEqual2}");
                Console.WriteLine($"AgeUp20:{AgeUp20}");
                Console.WriteLine($"AddressInKun:{AddressInKun}");
                Console.WriteLine($"JudgeAll:{JudgeAll}");
委托解耦实例
int LingNameEqual2 = (from Student student in delegateTest.students
                      where student.Name.Length == 2
                      select student).Count();
int LingAgeUp20 = (from Student student in delegateTest.students
                   where student.Age > 20
                   select student).Count();
int LingAddressInKun = (from Student student in delegateTest.students
                        where student.Address.Contains("昆山")
                        select student).Count();
int LingJudgeAll = (from Student student in delegateTest.students
                    where student.Name.Length == 2 && student.Age > 20 && student.Address.Contains("昆山")
                    select student).Count();
Console.WriteLine($"LingNameEqual2:{LingNameEqual2}");
Console.WriteLine($"LingAgeUp20:{LingAgeUp20}");
Console.WriteLine($"LingAddressInKun:{LingAddressInKun}");
Console.WriteLine($"LingJudgeAll:{LingJudgeAll}");
上方实例其实用linq更简单

十月的寒流  

  委托有什么用?1.将函数作为函数的参数进行传递,回调;2.声明事件并用来注册。微软提供了两个强类型委托:Action<T>和Func<T1,TResult>

  为什么要有多播委托?普通的委托+=和-=有什么不好?

1 调用委托时,如果其中的一个委托报错,则后面的不会被调用
2 只有最后一个的返回值才会作为委托的返回值
3 因为是数组,所有remove的复杂度是O(n
4 现成不安全

  委托为什么不等于函数指针?

1 委托可以“指向”多个函数
2 委托可以指向同一个函数多次
3 函数是包含在类中的,所以函数引用也包含了所在对象的信息;而C/C++的函数指针只是函数的入口地址

5.多播委托

  多播委托【+=】:为委托实例按顺序增加方法,形成方法链,Invoke时,按顺序依次执行。

  多播委托【-=】:为委托实例按顺序移除方法,从方法链的尾部开始匹配,遇到第一个完全吻合的,移除且只移除一个,没有也不异常。移除时不是同一个实例的方法移除不了。多播委托不能异步(BeginInvoke和EndInvoke)多播委托带返回值Invoke以最后的结果为准。

  多播委托的价值:一个变量保存多个方法,可以增减:invoke的时候可以按顺序执行。

//【1】定位委托
public delegate int WithReturnNoPara();

//【2】多播委托的三个方法
private int GetInt1()
{
    return 1;
}
private int GetInt2()
{
    return 2;
}
private int GetInt3()
{
    return 3;
}

public void Show()
{
    //【3】实例化委托
    WithReturnNoPara withReturnNoPara = new WithReturnNoPara(GetInt1);
    //【4】添加多播委托
    withReturnNoPara += new WithReturnNoPara(GetInt2);
    withReturnNoPara += new WithReturnNoPara(GetInt3);
    foreach (WithReturnNoPara dele in withReturnNoPara.GetInvocationList())
    {//遍历多播委托
        Console.WriteLine($"遍历结果  {dele.Invoke()}");
    }
    Console.WriteLine($"Invoke()方法返回值:{withReturnNoPara.Invoke()}");//多播委托带返回值Invoke以最后的结果为准
    //【5】减去多播委托的一个方法
    withReturnNoPara -= new WithReturnNoPara(GetInt3);
    foreach (WithReturnNoPara dele in withReturnNoPara.GetInvocationList())
    {
        Console.WriteLine($"遍历结果  -=之后{dele.Invoke()}");
    }
    Console.WriteLine($"Invoke()方法返回值:-=之后{withReturnNoPara.Invoke()}");
}
多播委托Code

 1 /* 多播委托应用举例,引入事件
 2  * 场景:一直神奇的猫,在它叫了一声之后会其他引发一系列的行为
 3  */
 4 //【1】定义委托
 5 public delegate void MiaoDelegate();
 6 public class Cat
 7 {
 8     //不适用多播委托和事件
 9     //直接调用别的实例别的方法,如果有一系列增删改,会让此方法不稳定
10     public void Miao()
11     {
12         Console.WriteLine("{0} Miao", this.GetType().Name);
13         new Mouse().Run();
14         new Baby().Cry();
15         new Mother().Wispher();
16         new Brother().Turn();
17         new Father().Roar();
18         new Neighbor().Awake();
19         new Stealer().Hide();
20         new Dog().Wang();
21     }
22 
23     //分析场景:猫叫了一声,引发一系列后续动作
24     //可以用多播委托将一系列动作封装出去【甩锅的概念】
25     //【2】定义委托实例
26     public MiaoDelegate MiaoDelegateHandler = null;
27     public void MiaoNew()
28     {
29         Console.WriteLine($"{this.GetType().Name}   叫了一声");
30         if (MiaoDelegateHandler != null)
31         {
32             MiaoDelegateHandler.Invoke();
33         }
34     }
35 
36     //事件的引入
37     public event MiaoDelegate MiaoDelegateHandlerEvent = null;
38     public void MiaoNewEvent()
39     {
40         Console.WriteLine($"{this.GetType().Name}   叫了一声");
41         if (MiaoDelegateHandlerEvent != null)
42         {
43             MiaoDelegateHandlerEvent.Invoke();
44         }
45     }
46 }
47 
48 
49 //多播委托应用
50 Cat cat = new Cat();
51 Console.WriteLine("~~~~~~~~~~~~~多播委托~~~~~~~~~~~~~");
52 cat.MiaoDelegateHandler += new MiaoDelegate(new Mouse().Run);
53 cat.MiaoDelegateHandler += new MiaoDelegate(new Baby().Cry);
54 cat.MiaoDelegateHandler += new MiaoDelegate(new Mother().Wispher);
55 cat.MiaoDelegateHandler += new MiaoDelegate(new Brother().Turn);
56 cat.MiaoDelegateHandler += new MiaoDelegate(new Father().Roar);
57 cat.MiaoDelegateHandler += new MiaoDelegate(new Neighbor().Awake);
58 cat.MiaoDelegateHandler += new MiaoDelegate(new Stealer().Hide);
59 cat.MiaoDelegateHandler += new MiaoDelegate(new Dog().Wang);
60 cat.MiaoNew();
多播委托之猫叫一声

5.事件event

   事件是带event关键字的委托的实例,event可以限制变量被外部调用/直接赋值,子类也不能调用。并且事件只能由声明者才能调用。

/* 多播委托应用举例,引入事件
 * 场景:一直神奇的猫,在它叫了一声之后会其他引发一系列的行为
 */
//【1】定义委托
public delegate void MiaoDelegate();
public class Cat
{
    //分析场景:猫叫了一声,引发一系列后续动作
    //可以用多播委托将一系列动作封装出去【甩锅的概念】
    //【2】定义委托实例
    public MiaoDelegate MiaoDelegateHandler = null;
    public void MiaoNew()
    {
        Console.WriteLine($"{this.GetType().Name}   叫了一声");
        if (MiaoDelegateHandler != null)
        {
            MiaoDelegateHandler.Invoke();
        }
    }

    //事件的引入
    public event MiaoDelegate MiaoDelegateHandlerEvent = null;
    public void MiaoNewEvent()
    {
        Console.WriteLine($"{this.GetType().Name}   叫了一声");
        if (MiaoDelegateHandlerEvent != null)
        {
            MiaoDelegateHandlerEvent.Invoke();
        }
    }
}


Cat cat = new Cat();
Console.WriteLine("~~~~~~~~~~~~~多播委托~~~~~~~~~~~~~");
cat.MiaoDelegateHandler += new MiaoDelegate(new Mouse().Run);
cat.MiaoDelegateHandler += new MiaoDelegate(new Baby().Cry);
cat.MiaoDelegateHandler += new MiaoDelegate(new Mother().Wispher);
cat.MiaoDelegateHandler += new MiaoDelegate(new Brother().Turn);
cat.MiaoDelegateHandler += new MiaoDelegate(new Father().Roar);
cat.MiaoDelegateHandler += new MiaoDelegate(new Neighbor().Awake);
cat.MiaoDelegateHandler += new MiaoDelegate(new Stealer().Hide);
cat.MiaoDelegateHandler += new MiaoDelegate(new Dog().Wang);
cat.MiaoNew();
Console.WriteLine("~~~~~~~~~~~~~事件~~~~~~~~~~~~~");
cat.MiaoDelegateHandlerEvent += new MiaoDelegate(new Mouse().Run);
cat.MiaoDelegateHandlerEvent += new MiaoDelegate(new Baby().Cry);
cat.MiaoDelegateHandlerEvent += new MiaoDelegate(new Mother().Wispher);
cat.MiaoDelegateHandlerEvent += new MiaoDelegate(new Brother().Turn);
cat.MiaoDelegateHandlerEvent += new MiaoDelegate(new Father().Roar);
cat.MiaoDelegateHandlerEvent += new MiaoDelegate(new Neighbor().Awake);
cat.MiaoDelegateHandlerEvent += new MiaoDelegate(new Stealer().Hide);
cat.MiaoDelegateHandlerEvent += new MiaoDelegate(new Dog().Wang);
cat.MiaoNewEvent();
多播委托与事件

  委托与事件的区别和联系?委托是一个类型,事件是委托的一个实例。事件是带event关键字的委托的实例,event可以限制变量被外部调用/直接赋值

5.事情与程序架构

  事件:可以把一堆可变的动作/行为封装出去,交给第三方来指定。和预定义一样,程序设计的时候,可以把程序分成两部分:一部分是固定的,直接写死;还有不固定的,通过一个事件去开放接口,外部可以随意扩展动作。

  框架:完成固定或通用部分,把可变部分留出扩展点,支持自定义。  

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委托的基本使用
Func<int,int,string> func = (x,y) => (x*y).ToString();
Consle.WriteLine(func(5,20));
使用lambda书写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.泛型再结

  委托三大意义:【1】委托解耦【2】异步多线程【3】

  泛型好处:类型安全、方便编码、无需拆装箱操作

  常见泛型:泛型类和泛型方法

  后续深入:泛型委托(自定义泛型委托、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定义在事件的发送者所在类中,委托调用的方法定义在事件的接收者所在类中,事件关联在主窗体内,事件代替方法实现调用在发送者所在类内。

十月的寒流

  希望一个类的某些成员在发生变化时能够被外界观测到,如CollectionChanged、TextChanged

  标准的.NET事件模式

1 delegate EventHander(object sender, EventArgs e)
2 EventArgs
3 Button.Click
4 TextBox.TextChanged

  推荐的命名规范:名词+动词(被动-ed) 

1 CollectionChanged
2 EventRaised
3 PropertyChanged
4 
5 OnEventRaised
6 OnPropertyChanged
7 RaisePropertyChange

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 }
异步编程同时执行多个任务
Action<string> action = this.DoSomethingLong;
IAsyncResult asyncResult = null;
AsyncCallback callback = ia =>
{
    Console.WriteLine(object.ReferenceEquals(asyncResult, ia));  //True
    Console.WriteLine(ia.AsyncState);  //"hao"
    Console.WriteLine($"到这里计算已经完成了。{Thread.CurrentThread.ManagedThreadId.ToString("00")}。");
};
asyncResult = action.BeginInvoke("btnAsyncAdvanced_Click", callback, "hao");

/// <summary>
/// 一个比较耗时耗资源的私有方法
/// </summary>
/// <param name="name"></param>
private void DoSomethingLong(string name)
{
    Console.WriteLine($"****************DoSomethingLong {name} Start {Thread.CurrentThread.ManagedThreadId.ToString("00")} {DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss.fff")}***************");
    long lResult = 0;
    for (int i = 0; i < 1000000000; i++)
    {
        lResult += i;
    }
    //Thread.Sleep(2000);

    Console.WriteLine($"****************DoSomethingLong {name}   End {Thread.CurrentThread.ManagedThreadId.ToString("00")} {DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss.fff")} {lResult}***************");
}
异步执行完毕去执行回调
Action<string> action = this.DoSomethingLong;
IAsyncResult asyncResult = null;
AsyncCallback callback = ia =>
{
    Console.WriteLine(object.ReferenceEquals(asyncResult, ia));  //True
    Console.WriteLine(ia.AsyncState);  //"hao"
    Console.WriteLine($"到这里计算已经完成了。{Thread.CurrentThread.ManagedThreadId.ToString("00")}。");
};
asyncResult = action.BeginInvoke("btnAsyncAdvanced_Click", callback, "hao");

asyncResult.AsyncWaitHandle.WaitOne();//等待任务的完成
asyncResult.AsyncWaitHandle.WaitOne(-1);//等待任务的完成
asyncResult.AsyncWaitHandle.WaitOne(1000);//等待;但是最多等待1000ms
异步信号量等待
//Func 带返回值委托
Func<int> func = () =>
  {
      Thread.Sleep(2000);
      return DateTime.Now.Day;
  };
//同步调用
Console.WriteLine($"func.Invoke()={func.Invoke()}");  

//异步调用
IAsyncResult asyncResult = func.BeginInvoke(r =>
 {
     int result = func.EndInvoke(r);  //可以在异步调用中等待执行结果,也可以在外部等待执行结果,但EndInvoke只能使用一次
     Console.WriteLine("状态:" + r.AsyncState);
     Console.WriteLine($"func.EndInvoke(asyncResult)={result}");
 }, "冰封的心");

//Console.WriteLine($"func.EndInvoke(asyncResult)={func.EndInvoke(asyncResult)}");
异步调用使用EndInvoke等待并接收返回值

 

异步的释放,调用EndInvoke就可以释放,不调由用CLR释放

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