C#:委托

1、委托是什么?

)委托是一种动态调用方法的类型,属于引用类型;
)委托是对方法的抽象和封装。委托对象实质上代表了方法的引用(即内存地址、指针);
)委托通常是委托某个方法来实现具体的功能。当我们调用委托的时候,委托包含的所有方法将被执行。虽然在定义委托时与方法有些相似,但我们不能将其称为方法;
)与委托绑定的方法方法签名(即返回值类型和形参列表)与委托一致;
)委托本质是一个密封类,所以可以在命名空间下定义,也可以在类里面声明;

1、继承自MulticastDelegate
2、委托的构造函数,需要传递一个方法作为参数
3、委托的内部有三个方法Invoke(同步委托),BeginInvoke(异步委托),EndInvoke(阻塞)

2、委托五步法(适合窗体之间传值使用)

1、委托(方法类型)的定义:
访问权限  delegate  返回值类型  委托类型名(形参列表);

2、委托变量的定义;
委托类型   委托变量名;

3、具体方法的定义:
访问权限  返回值类型  方法名(形参列表);

4、委托方法的绑定:
委托变量名=方法名;or  委托变量名=new  委托类型(方法名)

5、调用:
委托变量名(实参列表);

例:A类调用B类的方法,A是调用者(1、2、5),B是响应者(3、4)

  public delegate void DEL();  //1、委托(方法类型)的定义
    internal class Program
    {
        static void Main(string[] args)
        {
            Person person = new Person();
            person._del = Print;  //4、委托方法的绑定
            person._del =new DEL(Print);  
            person._del();  //5、调用
            person._del.Invoke();  //同步委托调用
        }
        public static void Print()  //3、具体方法的定义
        {
            Console.WriteLine("我是Program类的方法");
        }
    }
    class Person
    {
       public DEL _del;  //2、委托变量的定义
    }

 委托多窗体之间传值

建立两个窗体,主窗体和子窗体,UI界面分别如下

 

 子窗体传值给主窗体,要在主窗体上显示值,调用主窗体的显示值的方法,子窗体是调用者(1、2、5),主窗体是响应者(3、4)

步骤:1、在子窗体定义委托类型,委托变量
           2、主窗体创建与委托签名一致的方法,实例化子窗体,用对象.委托变量绑定主窗体方法
           3、子窗体用调用此方法

子窗体代码

 public delegate void DEL(string s);  //1
    public partial class ChirdForm : Form
    {
       public DEL _del;  //2
        public ChirdForm()
        {
            InitializeComponent();
        }

        private void button1_Click(object sender, EventArgs e)
        {
            _del(textBox1.Text);  //5
        }

 主窗体代码

 public partial class MainForm : Form
    {
        public string aaa { get; set; }
        ChirdForm chirdForm = new ChirdForm();
        public MainForm()
        {
            InitializeComponent();
        }

        private void button1_Click(object sender, EventArgs e)
        {
            chirdForm._del = Say;  //4
            chirdForm.Show();
        }
        public void Say(string s)  //3
        {
            this.textBox1.Text = s;
        }

        private void button2_Click(object sender, EventArgs e)
        {
            chirdForm.textBox2.Text = this.textBox1.Text;  //给子窗体传值
        }
    }

3、多播委托


委托变量可以绑定多个签名一样的方法,调用时按顺序全部调用(+=)
也可以用(-=)逐一解绑
注:在移除的方法的时候,必须是同一个(委托变量)实例绑定的方法才能移除,每个lambda表达式在底层会生成不同的方法名的,看起来一样实际是不同的方法

 static void Main(string[] args)
        {
            Person person = new Person();
            //多播委托追加绑定
            person._del = Print;  
            person._del += Ounter;
            person._del += () => { Console.WriteLine("我是Program类的方法3"); };

            //多播委托移除
            person._del -= Print;
            person._del -= Ounter;
            person._del -= () => { Console.WriteLine("我是Program类的方法3"); };  //移除失败,这是另一个方法
            person._del();  //5、调用
            Console.ReadKey();
        }

4、匿名委托(Lambda表达式)

匿名委托是指使用匿名方法注册在委托上,实际上是在委托中通过定义代码块来实现委托的作用

方法名使用关键字(delegate)代替 

例:使用匿名委托实现长方形面积

public delegate double DEL(double lenth,double width);  //定义委托类型(长、宽为参数,返回面积)
    internal class Program
    {
        static void Main(string[] args)
        {
            Console.Write("请输入长方形长:");
            double lenth=Convert.ToDouble(Console.ReadLine());
            Console.Write("请输入长方形宽:");
            double width = Convert.ToDouble(Console.ReadLine());
            DEL del = delegate (double l, double w)  //匿名委托
            {
                return l * w;  //方法体实现面积计算并返回
            };
           double sum= del(lenth, width);  //调用
            Console.WriteLine($"长方形的面积:{sum}");
            Console.ReadKey();
        }

lambda表达式:对匿名委托的简写
参数列表(变量)=>表达式(或语句块{})

简写上面题目

 public delegate double DEL(double lenth,double width);  //定义委托类型(长、宽为参数,返回面积)
    internal class Program
    {
        static void Main(string[] args)
        {
            Console.Write("请输入长方形长:");
            double lenth=Convert.ToDouble(Console.ReadLine());
            Console.Write("请输入长方形宽:");
            double width = Convert.ToDouble(Console.ReadLine());
            DEL del = (a,b)=>  //lambda表达式
            {
                return a * b;  //方法体实现面积计算并返回
            };
           double sum= del(lenth, width);  //调用
            Console.WriteLine($"长方形的面积:{sum}");
            Console.ReadKey();
        }

拆解:DEL del = (a,b)=>  a * b ;

(a,b)这里a和b变量对应委托类型声明时的形参列表,都是double类型
语句块只有一句表达式可以直接写在=>后面

这里完成了三步:
2、委托变量的定义;  3、具体方法的定义; 4、委托方法的绑定

5、框架内置委托(Action<>/Func<>

Action<>/Func<>是.NET Framework3.0时代的产物

1、Action<>
(1)Action<>是来自于System.RunTime的一个声明好的泛型委托,可以带有一个或者多个参数无返回值的委托,Action是无参无返回值委托类型
(2)最多支持16个入参,正常使用足够
2、Func<>
(1)Func<>是来自于System.RunTime的一个声明好的有返回值的委托,也可以有参数
(2)如果既然有参数也有返回值,前面是输入参数类型,最后面的作为返回值类型
(3)最多支持16个入参,正常足够使用

为什么要用框架内置委托?
(1)委托的本质是类,定义多个委托,其实就是新增了多个类,定义好的两个委托参数和返回值都是一致的,但是因为是不同的类,没有继承不能通用
(2)既然是系统框架给我们定义好了这两个委托,自然是希望我们在以后的开发中,都去使用这两个委托,这样就可以把委托类型做到统一
(3)那之前定义好的委托是去不掉的,这被称之为历史包袱

            #region Action
            Action act1 = () => { Console.WriteLine("我是无参无返回值"); };
            Action<int> act2 = a => { Console.WriteLine("我是有参无返回值"); };
            Action<int, string> act3 = (a, b) => { Console.WriteLine("我是有参无返回值"); };
            #endregion

            #region Func
            Func<int> func1 = () =>
            {
                Console.WriteLine("我是无参有返回值");
                return 1;
            };
            Func<int,string> func2 = a =>
            {
                Console.WriteLine("我是有参有返回值");
                return "";
            };
            #endregion

6、委托作为参数传递

static void Main(string[] args)
        {
            Print((a,b)=>
            {
                a++;
                b++;
            },10,20);
            Perit((a,b)=>
            {
               return a.ToString()+b.ToString();
            },20,23);
        }

        //定义委托参数方法
        public static void Print(Action<int,int> action,int a,int b)
        {
            action(a,b);            
        }
        public static string Perit(Func<int,int,string> func,int a,int b)
        {
           return func(a,b);
        }

注:委托,接口,值传递都和string一样,值传递到另一个方法赋值后,原始值不变

 public delegate void DEL();
    internal class Program
    {
        static void Main(string[] args)
        {
            DEL del=null;
            Person person=new Person(del);  //调用构造方法,给del绑定一个方法,但是由于委托有不变性,del还是为空
        }
    }
    class Person
    {
        public Person(DEL _del)   
        {
            _del = Print;
        }
        public void Print()
        {
            Console.WriteLine("llllllll");
        }
    }

7、匿名委托结合数组

创建People类,存放个体信息
创建Person类,把people类对象存入数组,并创建对应的方法
Main方法调用Person类确定数组元素个数,调用方法对数组元素进行处理

people类:
 

  public class People  //存放数组元素信息
    {
        public int ID { get; set; }  //学号
        public string Name { get; set; }  //姓名
        public double Gender { get; set; }  //分数
        public int PhoneNumber { get; set; }  //电话号码

        public void Print()
        {
            Console.WriteLine($"姓名:{Name},学号:{ID},分数:{Gender},电话号码:{PhoneNumber}");
        }
    }

person类:

 public class Person
    {
        People[] peoples=null;  //创建一个学生类
        public int count = 0;  //数组长度

        public void Add(People pe)  //添加元素的方法
        {
            if (count > 0)  //判断数组是否为空
            {
                People[] item=new People[count];
                for (int i = 0; i < count; i++)  //原数组值存放临时数组
                {
                    item[i] = peoples[i];
                }
                count++;
                peoples = null;  //清空原数组
                peoples = new People[count];  //重置原数组长度
                for (int i = 0; i < item.Length; i++)  //临时数组放回原数组值
                {
                    peoples[i]=item[i];   //这时peoples数组最后一个值是空的
                }
            }
            else
            {
                count++;
                peoples = new People[count];  //重置原数组长度,这时peoples数组最后一个值是空的
            }
            peoples[count - 1] = pe;  //存放数组元素
        }
        public void Prin()  //打印数组方法
        {
            foreach (People item in peoples)
            {
                item.Print();
            }
        }

        //筛选方法,这里用到泛型委托,一个参数为People类对象,好处是调用时可以用lambda表达式去筛选条件打印
        public void Scree(Action<People> action) 
        {
            foreach(People item in peoples)
            {
                action(item);
            }
        }
        public bool IsOrTrue(Func<People,bool> func)  //判断是否有无
        {
            foreach (var item in peoples)
            {
                if (func(item))  //因为func返回的是一个bool值,所以在方法里充当条件使用
                {
                    return true;
                }
            }
            return false;
        }
    }

Main函数调用

internal class Program
    {
        static void Main(string[] args)
        {
            Person per = new Person();
            per.Add(new People() { ID = 1, Name = "小明", Gender = 80, PhoneNumber = 15845454326 });
            per.Add(new People() { ID = 2, Name = "小花", Gender = 58, PhoneNumber = 17485454321 });
            per.Add(new People() { ID = 3, Name = "小猪", Gender = 88, PhoneNumber = 18858845328 });
            per.Add(new People() { ID = 4, Name = "小狗", Gender = 99, PhoneNumber = 12545455824 });
            per.Add(new People() { ID = 5, Name = "小猫", Gender = 25, PhoneNumber = 19945584355 });

            per.Prin();  //打印全部学生信息
            per.Scree(a=>
            {
                if (a.ID == 2)  //找出学号2的学生
                {
                    a.Print();
                }
            });
            per.Scree(a =>
            {
                if (a.Gender >80)  //找出分数大于80的学生
                {
                    a.Print();
                }
            });
           bool b1= per.IsOrTrue(a=>  //班上是否有姓名是小明的学生
            {
               return a.Name == "小明";
            });
            Console.WriteLine(b1);
            bool b2 = per.IsOrTrue(a =>
            {
               return a.Gender > 95;  //班上是否有分数大于95的学生
            });
            Console.WriteLine(b2);
            Console.ReadKey();
        }
}

8、匿名委托结合列表

创建Student类,存放个体信息
Main函数调用系统方法

Student类

public class Student
    {
        public int ID { get; set; }  //学号
        public string Name { get; set; }  //姓名 
        public string SubjectName { get; set; }  //考试科目  
        public int ScoreValue { get; set; }  //考试成绩

        public Student(int iD, string name, string subjectName, int scoreValue)
        {
            ID = iD;
            Name = name;
            SubjectName = subjectName;
            ScoreValue = scoreValue;
        }

        public void Print()
        {
            Console.WriteLine("学号:{0} 姓名:{1} 考试科目:{2} 考试成绩:{3}", this.ID, this.Name, this.SubjectName, this.ScoreValue);
        }
    }

Main函数调用

        static void Main(string[] args)
        {
            List<Student> socre = new List<Student>() 
            {
                new Student(1,"马老师","语文",90),
                new Student(1,"马老师","数学",80),
                new Student(1,"马老师","英语",70),

                new Student(2,"达文西","语文",75),
                new Student(2,"达文西","数学",56),
                new Student(2,"达文西","英语",65),

                new Student(3,"鸽鸽","语文",79),
                new Student(3,"鸽鸽","数学",76),
                new Student(3,"鸽鸽","英语",80),
            };

            foreach (Student s in socre)
            {
                s.Print();
            }
            //求各个同学总分与平局分
            for (int i = 1; i <= 3; i++)
            {
                List<Student> students = socre.FindAll(t => t.ID == i);//找到匹配的学号
                Console.WriteLine($"{students[0].Name}-总分:\t{students.Sum(t => t.ScoreValue):0.00}" );
                Console.WriteLine($"{students[0].Name}-平均分:\t{students.Average(t => t.ScoreValue):0.00}" );
                Console.WriteLine("===============================================================");
            }

            //求全部同学的数学平均分
            double AvgHalcon = socre.Where(t => t.SubjectName == "数学").Average(t => t.ScoreValue);
            Console.WriteLine($"数学平均分:\t{AvgHalcon:0.00}" );
            Console.WriteLine("===============================================================");

            //求全部同学的语文平均分
            double AvgCSharp = socre.Where(t => t.SubjectName == "语文").Average(t => t.ScoreValue);
            Console.WriteLine($"语文平均分:\t{AvgCSharp:0.00}" );
            Console.WriteLine("===============================================================");

            //查找低于60分的同学,打印输出
            Console.WriteLine("低于60分的同学:");
            socre.FindAll(t => t.ScoreValue < 60).ForEach(t=>t.Print());
            Console.WriteLine("===============================================================");

            //查询学号为2的同学数学考试成绩
            Student MathSocre = socre.FirstOrDefault(t => t.ID == 2 && t.SubjectName == "数学");
            Console.WriteLine($"学号为2的同学数学考试成绩:{MathSocre.ScoreValue}");
            Console.WriteLine("===============================================================");

            //求数学科目的最高分与最低分
            int MaxMath = socre.Where(t => t.SubjectName == "数学").Max(t => t.ScoreValue);
            int MinMath = socre.Where(t => t.SubjectName == "数学").Min(t => t.ScoreValue);
            //打印输出最高分与最低分
            Console.WriteLine($"数学科目的最高分:\t{MaxMath}");
            Console.WriteLine($"数学科目的最低分:\t{MinMath}" );
            Console.WriteLine("===============================================================");
            Console.ReadKey();
        }

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值