event(事件)就是delegate(代理),event能做到的事情delegate都能做到。
而delegate可以认为是一种函数指针
1.先用函数指针来做例子,C++代码
//函数指针,指向的类型为参数为空,返回值也为空的函数
void (*pFun)();
void Fun3(){
cout << "Fun3" << endl;
}
//在代用Fun1()前先将函数指针pFun指向Fun2()函数
int main(){
pFun = Fun3();
pFun();
return 0;
}
2.delegate的例子
public delegate void Del();
class Program
{
static void Main(string[] args)
{
Del del = Fun;
del += Fun;
del.Invoke();
Console.ReadLine();
}
public static void Fun()
{
Console.WriteLine();
}
}
delegate的声明形式是:public delegate void Del();; 这和函数指针的声明形式基本一样:void (*pFun)();
上面的函数指针和delegate代码说明,函数指针和delegate是非常像的,作用也是非常像的。
delegate具有多播的能力,即可以同时绑定多个方法,正如例子中所展示的。
个人理解delegate:
delegate是一种类型,和string,int,class一样,是一种类型。每一种类型都是一种约束,约束了该类型的各种能力(比如string就是字符串的各种操作,int就是整数的各种操作)。而delegate作为一种类型,他也有自己的约束,就是他指向的是一类方法(函数)。当定义了一个delegate的类型时:
public delegate void Del();//此句中的delegate是一个标识符,而Del才是真正的delegate类型
Del del;//del表示Del这个delegate类型的实例
del这个实例就和函数指针void (*pFun)()一样,可以指向一个参数为空,返回值也为空的方法。可以在原本需要调用这个方法时用del就代替这个方法的位置,但前提是,将方法绑定到del上。
在有了delegate程序就可以灵活很多了。原本在程序中固定的方法可以用delagate代替,然后动态的传递符合要求的方法。
这样可以使一些底层的方法不需要改了,只要改上层的逻辑就可以了。
个人理解event:
event就是一个delegate,event能做到的,delegate都能做到。
但是不希望event拥有太多delegate的属性,就采用event。
event即事件。事件表示某一个动作发生或某一个时机到来的时候,紧接着会产生某一个动作。
public void Fun1(){
Fun2();
}
public void Fun2(){
}
上面的例子中,每当Fun1()方法被调用的时候,Fun2()必定被调用。那么Fun2就是一个事件,该事件的触发条件就是当Fun1被调用。
private int price;
public int Price
{
get { return price; }
set
{
price = value;
if (price > 10)
{
Fun2();
}
}
}
上面的例子中,每当price>10时,Fun2都会被触发。那么这个例子中的Fun2()也是一个事件,该事件的触发条件就是price>10。
可以说,事件本身其实就是一个函数。只不过它的调用时机不是任意的,而是固定在某一个节点上。
像上面的例子中,事件直接用方法来替代的做法不是很聪明,因为太死板了。我们何不用delegate来代替这个方法,可以做到灵活多变。这样底层的代码就可以不用修改了,我们的需求改变时,只要增加新的方法就行了(对修改关闭,对添加开放)。
使用delegate的例子:
delegate void OnClick(string key);
class Program
{
static void Main(string[] args)
{
//可以动态绑定我们需要的方法
OnClick onclick = ShowLower;
//onclick += ShowUpper;
while (true)
{
Console.Write("input:");
onclick(Console.ReadLine());
}
Console.ReadLine();
}
//将输入的字符串变小写
public static void ShowLower(string key)
{
Console.WriteLine("output:" + key.ToLower());
}
//将输入的字符串变大写
public static void ShowUpper(string key)
{
Console.WriteLine("output:" + key.ToUpper());
}
}
在前文中说过,event能够做的事,delegate都能做,而且event就是delagate中的特殊情况。那为什么我们还要创建event呢。因为当我们定义delegate时,delegate会包含很多对delagate的操作,可以从外部来直接操作这个delegate。所以用event来限制外部对delagate其余方法的调用,让外部只能添加和删除delegate绑定的方法。
使用event的例子:
也可以将上述例子使用event代替
delegate void OnClick(string key);
class Program
{
private static event OnClick onclick;
static void Main(string[] args)
{
onclick = ShowLower;
//onclick += ShowUpper;
while (true)
{
Console.Write("input:");
onclick(Console.ReadLine());
}
Console.ReadLine();
}
public static void ShowLower(string key)
{
Console.WriteLine("output:" + key.ToLower());
}
public static void ShowUpper(string key)
{
Console.WriteLine("output:" + key.ToUpper());
}
}
上面的event是语法级别的,可以这么使用,但并不符合逻辑。
使用event更好的例子。
气象台和广播。1个气象台,多个地方广播,每个地方广播有自己的特色。每当气象台的温度改变时,各个广播会自动的播报。
public delegate void TempChangeEventHandler(int temp);
class Program
{
static void Main(string[] args)
{
Center center = new Center(25);
center.tempChangeEvent += 东部电视台;
center.tempChangeEvent += 西部电视台;
center.tempChangeEvent += 中部电视台;
while (true)
{
Console.WriteLine("当前温度:{0}",center.Temperature);
Console.Write("新温度为:");
center.Temperature = int.Parse(Console.ReadLine());
}
Console.ReadLine();
}
public static void 东部电视台(int temp)
{
Console.WriteLine($"东部电视台:当前温度为{temp}℃, 生活愉快");
}
public static void 西部电视台(int temp)
{
Console.WriteLine($"西部电视台:当前温度为{temp}℃, 欢迎大家来游玩");
}
public static void 中部电视台(int temp)
{
Console.WriteLine($"中部电视台:当前温度为{temp}℃, 请适当增减衣物");
}
}
public class Center
{
public TempChangeEventHandler tempChangeEvent;
private int _temperature;
public int Temperature
{
get => _temperature;
set
{
if (value != _temperature)
{
_temperature = value;
tempChangeEvent(_temperature);
}
}
}
public Center(int temperature)
{
_temperature = temperature;
}
}
但是C#定义了一套专门的事件框架,最好使用这个框架。
class Program
{
static void Main(string[] args)
{
Center center = new Center(25);
center.tempChangeEvent += 东部电视台;
center.tempChangeEvent += 西部电视台;
center.tempChangeEvent += 中部电视台;
while (true)
{
Console.WriteLine("当前温度:{0}",center.Temperature);
Console.Write("新温度为:");
center.Temperature = int.Parse(Console.ReadLine());
}
Console.ReadLine();
}
public static void 东部电视台(object sender, TempEventArgs e)
{
Console.WriteLine($"东部电视台:当前温度为{e.Temp}℃, 生活愉快");
}
public static void 西部电视台(object sender, TempEventArgs e)
{
Console.WriteLine($"西部电视台:当前温度为{e.Temp}℃, 欢迎大家来游玩");
}
public static void 中部电视台(object sender, TempEventArgs e)
{
Console.WriteLine($"中部电视台:当前温度为{e.Temp}℃, 请适当增减衣物");
}
}
public class Center
{
public EventHandler<TempEventArgs> tempChangeEvent;
private int _temperature;
public int Temperature
{
get => _temperature;
set
{
if (value != _temperature)
{
_temperature = value;
tempChangeEvent?.Invoke(this, new TempEventArgs(_temperature));
}
}
}
public Center(int temperature)
{
_temperature = temperature;
}
}
//事件中需要的参数
public class TempEventArgs : EventArgs
{
public int Temp;
public TempEventArgs(int temp)
{
Temp = temp;
}
}
可以对比两者的区别。