委托与事件
委托(Delegate)
什么是委托
- 委托:是一种特殊的类,是存有对某个方法的引用的一种引用类型变量,对一类方法的抽象。
- 用处:常用于实现事件和回调方法。
声明委托
声明委托:相当于声明一个类,委托在声明的时候就决定好了它可以引用方法的参数和返回值。
例如下面的委托,它就只能引用带有两个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();
}
}
}
其它四种形式的委托
- delegate定义的匿名委托
使用情况:有些方法只用到了一次,这样的方法在类里面过多就容易使得程序的可读性不好。
//实例化委托里面的AttackDelegate委托写的
AttackDelegate ad = delegate(string name, string target) {
Console.WriteLine(name + "被" + target + "丢出了场外");
};
- lambda表达式
Lambda表达式实际上是一种匿名函数,使用Lambda表达式可大大减少代码量,使得代码更加的优美、简洁,更有可观性。
lambda表达式格式:(参数)=>{要执行的代码}
AttackDelegate ad = (string name, string target) => {
Console.WriteLine(name + "被" + target + "丢出了场外");
};
- 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();
}
}
}
- 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)
什么是事件
- 事件:对象用于(向系统中的所有相关组件)广播已发生事情的一种方式。 任何其他组件都可以订阅事件,并在事件引发时得到通知。
- 事件声明的方式:事件是基于委托实现的,委托可以使用自定义委托或者使用EventHandler系统自己的带参委托,通过Event关键字来声明。
- 用处:可以解耦。事件是一个发布-订阅的模式,发布者不需要知道谁是订阅者,这样就可以在解耦的发布者中编程。例如,游戏中逻辑和视图操作,逻辑中玩家升级了,而对应的视图(等级、特效、角色时装等)只需要订阅就能收到升级的广播。
通过自定义委托类,声明使用事件
第一步:自定义一个委托类。
第二步:利用自定义委托类来声明一个事件。
第三步:定义一个方法来调用事件
第四步:定义一个处理方法。
第五步:让处理方法订阅事件。
下面是一个老师布置作业给学生的例子。
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();
}
}
}
事件注意
- 事件只能通过“+=”和“-=”的方式注册和取消订户处理函数,而委托除此之外还可以使用“=”直接赋值处理函数。
疑问(以后想明白再补充):
- 委托和事件使用情形的不同,虽然文档里面有,但现在还不是很明白。(C#中文文档:区别委托和事件)