委托(Delegate)
C# 中的委托(Delegate)类似于 C 或 C++ 中函数的指针。
委托(Delegate)特别用于实现事件和回调方法。所有的委托(Delegate)都派生自 System.Delegate 类(委托是一个类!!)
委托的定义:
public delegate int NumberChanger(int n);
委托的实例化:
NumberChanger nc1 = new NumberChanger(AddNum); //后面的AddNum是方法名
NumberChanger nc2 = new NumberChanger(MultNum);
注意:委托的定义和方法名一样,比如AddNum的定义是public static int AddNum(int p)
,注意返回值和参数类型
委托的调用:
int res = nc1(25);
和原方法的调用一样
委托的多播(Multicasting of a Delegate)
委托对象可使用 “+” 运算符进行合并。(注意:!相同类型!才能合并)
“-” 运算符可用于从合并的委托中移除组件委托。
委托的 多播(multicasting):意思就是利用委托的合并性质,把方法A、B、C…的调用组成一个调用列表。
例如:
// 创建委托实例
NumberChanger nc;
NumberChanger nc1 = new NumberChanger(AddNum);
NumberChanger nc2 = new NumberChanger(MultNum);
nc = nc1;
nc += nc2;
// 调用多播
nc(5);
其实上面nc(5)相当于MultNum(AddNum(5))
以后我每次调用nc就可以调用一坨。比较方便
事件(Event)
事件(Event) 基本上说是一个用户操作,如按键、点击、鼠标移动等等;或者是一些提示信息,如系统生成的通知。应用程序需要在事件发生时响应事件。例如,中断。
C# 中使用事件机制实现线程间的通信。
1. 声明事件(Event)
在类的内部声明事件,首先必须声明该事件的委托类型。例如:
public delegate void BoilerLogHandler(string status);
然后,声明事件本身,使用 event 关键字:
public event BoilerLogHandler BoilerEventLog;
上面的代码定义了一个名为 BoilerLogHandler 的委托和一个名为 BoilerEventLog 的事件,该事件在生成的时候会调用委托。
2. 事件实例
using System;
namespace DelegateAndEvent
{
//定义一个事件类
public class MyEvent
{
//定义一个委托
public delegate void MyDelegate();
//定义一个事件
public event MyDelegate MyDelegateEvent;
//定义一个触发事件的函数
public void OnMyDelegateEvent()
{
//判断事件是否非空
if (MyDelegateEvent != null)
{
//执行事件
MyDelegateEvent();
}
//MyDelegateEvent?.Invoke(); //简化的判断和执行
}
}
class Program
{
//输出一串字符
public static void putOutChar()
{
Console.WriteLine("I was fired");
}
//输出第二串字符
public static void putOutChar2()
{
Console.WriteLine("I was fired22222");
}
static void Main(string[] args)
{
//实例化MyEvent2类
MyEvent myEvent = new MyEvent();
//注册一个事件
myEvent.MyDelegateEvent += new MyEvent.MyDelegate(putOutChar);
myEvent.MyDelegateEvent += new MyEvent.MyDelegate(putOutChar2);
//执行触发事件的函数
Console.WriteLine("执行绑定了两个事件后的函数");
myEvent.OnMyDelegateEvent();
//解绑一个事件
myEvent.MyDelegateEvent -= new MyEvent.MyDelegate(putOutChar);
//再次执行触发事件的函数
Console.WriteLine("执行解绑了一个事件后的函数");
myEvent.OnMyDelegateEvent();
Console.ReadKey();
}
}
}
注意点:
- 委托有啥用?
用来表明事件的调用类型。比如:Exploded("sorry,this car is dead")
,那么其委托就是public delegate void CarEngineHandler(string msg);
委托多播的实例代码:
委托多播
using System;
delegate int NumberChanger(int n);
namespace DelegateAppl
{
class TestDelegate
{
static int num = 10;
public static int AddNum(int p)
{
num += p;
return num;
}
public static int MultNum(int q)
{
num *= q;
return num;
}
public static int getNum()
{
return num;
}
static void Main(string[] args)
{
// 创建委托实例
NumberChanger nc;
NumberChanger nc1 = new NumberChanger(AddNum);
NumberChanger nc2 = new NumberChanger(MultNum);
nc = nc1;
nc += nc2;
// 调用多播
nc(5);
Console.WriteLine("Value of Num: {0}", getNum());
Console.ReadKey();
}
}
}
事件的实例代码:
C#事件代码
using System;
namespace CarEvent
{
public class Car
{
// 申明委托
public delegate void CarEngineHandler(string msg);
// 创建委托实例Exploded和AboutToBlow事件
public event CarEngineHandler Exploded;
public event CarEngineHandler AboutToBlow;
//设置属性
public int CurrentSpeed { get; set; }
public int MaxSpeed { get; set; }
public string PetName { get; set; }
public bool CarIsDead;//用于判断是否超速
public Car()//构造函数
{
MaxSpeed = 100;
}
public Car(string name, int maxSp, int currSp)//构造函数重载
{
CurrentSpeed = currSp;
MaxSpeed = maxSp;
PetName = name;
}
public void Accelerate(int delta)//用于触发Exploded和AboutToBlow事件
{
CurrentSpeed += delta;//"踩油门"加速
if (CurrentSpeed >= MaxSpeed)//判断时速
CarIsDead = true;
else
CarIsDead = false;
if (CarIsDead)// 如果Car超速了,触发Exploded事件
{
if (Exploded != null)//判断是否被委托联系起来
{
Exploded("sorry,this car is dead");//调用CarDead事件
}
}
else
{ //如果没有超速,则提示快要超速并显示实时车速
if ((MaxSpeed - CurrentSpeed) > 0 && (MaxSpeed - CurrentSpeed) <= 10 && AboutToBlow != null)//判断是否被委托联系起来且速度是否接近临界值
{
AboutToBlow("careful buddy ! gonna blow !");//调用NearDead事件
Console.WriteLine("CurrentSpeed={0}",CurrentSpeed);//显示实时车速
}
}
}
}
//订阅类书写举例
public class Answer
{
public void CarDead(string msg)//汽车已爆缸事件
{
Console.WriteLine("sorry,this car is dead");
}
public void NearDead(string msg)//汽车快要爆缸事件
{
Console.WriteLine("careful buddy ! gonna blow !");
}
}
//主函数书写
public class test
{
static void Main(string[] args)
{
Car c = new Car("奔驰",100,93);//创建实例并初始化,初始速度为93
Answer an = new Answer();
c.Exploded += new Car.CarEngineHandler(an.CarDead);//Exploded"绑定"CarDead
c.AboutToBlow += new Car.CarEngineHandler(an.NearDead);//AboutToBlow"绑定"NearDead
c.Accelerate(6);//第一次加速,时速小于100,引发的事件为"快要爆缸"并显示实时车速为99
Console.ReadLine();//等待回车键已启动第二次加速
c.Accelerate(2);//第二次加速,时速超过100,引发的事件为"已爆缸",不显示车速
Console.ReadKey();
}
}
}
结果为:
"careful buddy ! gonna blow !"
"CurrentSpeed=99"
(空行)(一定要记得敲一下回车键,不然不会显示下面字符串)
"sorry,this car is dead"