C#知识点(2)委托与事件

委托(Delegate)

什么是委托

  1. 委托:是一种特殊的,是存有对某个方法的引用的一种引用类型变量,对一类方法的抽象。
  2. 用处:常用于实现事件和回调方法。

声明委托

声明委托:相当于声明一个类,委托在声明的时候就决定好了它可以引用方法的参数和返回值。
例如下面的委托,它就只能引用带有两个int参数和返回一个int类型变量的方法。

public delegate int calculate(int a,int b);

实例化委托

实例化委托:委托对象必须使用 new 关键字来创建,传入参数就是方法的名字。还可以把委托作为参数,并使用它调用方法。

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace Blog1
{
    //定义委托,定义可以引用方法的类型
    public delegate void AttackDelegate(string name, string target);
    class Program
    {
        //直拳
        private static void CrossFistAttack(string name, string target)
        {
            Console.WriteLine(name+"对"+target+"直拳");
        }
        //摆拳
        private static void HookFistAttack(string name, string target)
        {
            Console.WriteLine(name + "对" + target + "摆拳");
        }
        // 还可以把委托作为参数,并使用它调用方法
        private static void AttackMove(AttackDelegate AD)
        {
            AD("小红","小明");
        }
        static void Main(string[] args)
        {
            //创建委托实例
            AttackDelegate attack1 = new AttackDelegate(CrossFistAttack);
            AttackDelegate attack2 = new AttackDelegate(HookFistAttack);
            //使用委托对象调用方法
            attack1("小明","小华");
            attack2( "小华","小明");
            AttackMove(attack1);
            //输入可以暂停显示,用来方便查看输出
            Console.ReadLine();
        }
    }
}

委托的多播(Multicasting of a Delegate)

委托的多播:委托对象可使用 “+” 运算符进行合并,让一个合并委托调用它所合并的两个委托。"-" 运算符可用于从合并的委托中移除组件委托。
注意:只有相同类型的委托可被合并。

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace Blog1
{
    //定义委托,定义可以引用方法的类型
    public delegate void AttackDelegate(string name, string target);
    class Program
    {
        //直拳
        private static void CrossFistAttack(string name, string target)
        {
            Console.WriteLine(name+"对"+target+"直拳");
        }
        //摆拳
        private static void HookFistAttack(string name, string target)
        {
            Console.WriteLine(name + "对" + target + "摆拳");
        }
        static void Main(string[] args)
        {
            //创建委托实例
            AttackDelegate ad;
            AttackDelegate attack1 = new AttackDelegate(CrossFistAttack);
            AttackDelegate attack2 = new AttackDelegate(HookFistAttack);
            //委托的多播
            ad = attack1;
            ad += attack2;
            ad("小明","小华");
            ad -= attack1;
            ad("小华", "小明");
            //输入可以暂停显示,用来方便查看输出
            Console.ReadLine();
        }
    }
}

其它四种形式的委托

  1. delegate定义的匿名委托
    使用情况:有些方法只用到了一次,这样的方法在类里面过多就容易使得程序的可读性不好。
//实例化委托里面的AttackDelegate委托写的
AttackDelegate ad = delegate(string name, string target) {
	Console.WriteLine(name + "被" + target + "丢出了场外");
};
  1. lambda表达式
    Lambda表达式实际上是一种匿名函数,使用Lambda表达式可大大减少代码量,使得代码更加的优美、简洁,更有可观性。
    lambda表达式格式:(参数)=>{要执行的代码}
AttackDelegate ad = (string name, string target) => {
	Console.WriteLine(name + "被" + target + "丢出了场外");
};
  1. Func委托
    内置的有返回值的泛型委托,可以接受0个至16个传入参数。
namespace Blog1
{
    class Program
    {
        public static int Addtion(int x,int y)
        {
            return x + y;
        }
        static void Main(string[] args)
        {
            Func<int, int, int> addtion = Addtion;//Func<输入类型,输出类型>
            int result = addtion(100, 2);
            Console.WriteLine(result);
            Console.ReadLine();
        }
    }
}
  1. Action委托
    内置的无返回值的泛型委托,可以接受0个至16个传入参数。
namespace Blog1
{
    class Program
    {
        public static void Addtion(int x,int y)
        {
            Console.WriteLine(x+y);
        }
        static void Main(string[] args)
        {
            Action<int, int> addtion = Addtion;
            addtion(100, 2);
            Console.ReadLine();
        }
    }
}

事件(Event)

什么是事件

  1. 事件:对象用于(向系统中的所有相关组件)广播已发生事情的一种方式。 任何其他组件都可以订阅事件,并在事件引发时得到通知。
  2. 事件声明的方式:事件是基于委托实现的,委托可以使用自定义委托或者使用EventHandler系统自己的带参委托,通过Event关键字来声明。
  3. 用处:可以解耦。事件是一个发布-订阅的模式,发布者不需要知道谁是订阅者,这样就可以在解耦的发布者中编程。例如,游戏中逻辑和视图操作,逻辑中玩家升级了,而对应的视图(等级、特效、角色时装等)只需要订阅就能收到升级的广播。

通过自定义委托类,声明使用事件

第一步:自定义一个委托类。
第二步:利用自定义委托类来声明一个事件。
第三步:定义一个方法来调用事件
第四步:定义一个处理方法。
第五步:让处理方法订阅事件。
下面是一个老师布置作业给学生的例子。

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace Blog1
{
    //自己声明一个委托
    public delegate void HomeworkDelegate(string work_name);
    public class Student
    {
        private string student_name;
        public Student(string name)
        {
            this.student_name = name;
        }
        //订阅老师作业事件
        public void Subscribe(Teacher teacher)
        {
            teacher.HomeworkEvent += OnHomework;
        }
        //处理方法
        public void OnHomework(string work_name)
        {
            Console.WriteLine(student_name + "需要完成" + work_name + "作业");
        }
    }
    public class Teacher
    {
        //利用自定义委托类来声明一个事件
        public event HomeworkDelegate HomeworkEvent;
        //调用事件方法
        public void Assignment(string work_name)
        {
            /*
            这段注释代码和HomeworkEvent?.Invoke(workName)作用一样
            if (HomeworkEvent != null)
            {
                HomeworkEvent(workName);
            }
             */
            HomeworkEvent?.Invoke(work_name);

        }
    }
    class Program
    {
        
        static void Main(string[] args)
        {
            Student stu1 = new Student("小明");
            Student stu2 = new Student("小华");
            Student stu3 = new Student("小红");
            Teacher teacher = new Teacher();
            stu1.Subscribe(teacher);
            stu2.Subscribe(teacher);
            stu3.Subscribe(teacher);
            teacher.Assignment("C#编写hellow world");
            Console.ReadLine();
        }
    }
}

通过EventHandler系统定义委托类,声明使用事件

第一步:编写参数,通常是派生自 System.EventArgs
第二步:用系统定义的泛型委托类:EventHandler。
第三步:定义一个方法来调用事件
第四步:定义一个处理方法。
第五步:让处理方法订阅事件。
下面的例子是把自定义委托类的改成EventHandler的写法。

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace Blog1
{
    //编写参数,派生自 System.EventArgs
    public class HomeworkArgs : EventArgs
    {
        public string Work_Name { get; }
        public HomeworkArgs(string work_name)
        {
            Work_Name = work_name;
        }
    }
    public class Student
    {
        private string student_name;
        public Student(string name)
        {
            this.student_name = name;
        }
        //订阅老师作业事件
        public void Subscribe(Teacher teacher)
        {
            teacher.HomeworkEvent += OnHomework;
        }
        //处理方法
        //方法标准签名:void 函数名(object sender, EventArgs args)
        public void OnHomework(object sender, HomeworkArgs e)
        {
            Console.WriteLine(student_name + "需要完成" + e.Work_Name + "作业");
        }
    }
    public class Teacher
    {
        //public event HomeworkDelegate HomeworkEvent;
        public event EventHandler<HomeworkArgs> HomeworkEvent;
        //调用事件方法
        public void Assignment(string work_name)
        {
            /*
            这段注释代码和HomeworkEvent?.Invoke(workName)作用一样
            if (HomeworkEvent != null)
            {
                HomeworkEvent(workName);
            }
             */
            HomeworkEvent?.Invoke(this, new HomeworkArgs(work_name));

        }
    }
    class Program
    {
        
        static void Main(string[] args)
        {
            Student stu1 = new Student("小明");
            Student stu2 = new Student("小华");
            Student stu3 = new Student("小红");
            Teacher teacher = new Teacher();
            stu1.Subscribe(teacher);
            stu2.Subscribe(teacher);
            stu3.Subscribe(teacher);
            teacher.Assignment("C#编写hellow world");
            Console.ReadLine();
        }
    }
}

事件注意

  1. 事件只能通过“+=”和“-=”的方式注册和取消订户处理函数,而委托除此之外还可以使用“=”直接赋值处理函数。

疑问(以后想明白再补充):

  1. 委托和事件使用情形的不同,虽然文档里面有,但现在还不是很明白。(C#中文文档:区别委托和事件
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值