CSharp事件和委托
委托与事件在开发中的应用非常广泛,本文将简单介绍C#中委托和事件的定义、使用方法,以及它们之间的区别和联系。
委托
C#中的委托(delegate)类似于C/C++中的函数指针,是一种存在对某个方法的引用的引用类型变量,所有的委托都派生自System.Delegate
类。
委托的声明
声明委托的语法如下:
delegate <return type> <delegate name> <parameter list>
比方说,我要声明一个无返回值,无参数的委托。
public delegate void MyDelegate();
在声明了委托类型后,必须将其实例化才能生效,可以使用new关键字创建并传入参数(参数为一个特定的方法名)。
MyDelegate myDelegate = new MyDelegate(Func1);
以上实例中我们实例化了一个带有Func1方法引用的MyDelegate类型变量,并将其赋值给了myDlegate实例。
委托的调用
如果想让委托调用它所引用的方法,可以直接仿照方法调用的写法。
myDelegate();
多播委托
其实一个委托类型的变量可以同时包含多个方法的引用,如果要在委托实例化后对方法引用进行增删操作,可以使用+=或-=运算符。
例如我们要给myDelegate添加Func2和Func3方法并删除对Func1方法的引用。
myDelegate += Func2;
myDelegate += Func3;
myDelegate -= Func1;
预定义委托
在.NET Framework 3.5以来,提供了很多的泛型委托,原先需要手动定义的现在可以直接使用了。
Action委托
Action委托代表返回为空的委托,以下示例实例化一个Action委托,并引用Plus方法。
public void Plus(int a,int b){
Console.WriteLine(a + b);
}
Action<int,int> a = Plus;
泛型类型指定为方法的参数类型,最多可指定16个。
Func委托
Func委托代表返回值非空的委托,以下实例化一个Func委托,并引用ConnectString方法。
public string ConnectString(string s1,string s2){
return s1 + s2;
}
Func<string,string,string> f = ConnectString;
最后一位泛型类型指定方法的返回值类型,前面各类型指定方法参数类型,同样最多指定16个。
事件
事件(Event)可以理解为一种封装好的委托,用于程序对用户的某些操作进行响应。事件在类内声明,通过使用同一个类或其他类中的委托与事件处理程序相关联。
通过委托创建事件
事件的声明
事件声明方法与实例化委托很类似,不同之处在于需要在委托类型前加上event关键字。
public delegate void MyDelegate();
public event MyDelegate myEvent;
与委托变量的区别
事件只能作为类的成员变量
class DelegateClass{ public delegate void MyDelegate(); public event MyDelegate myEvent1; //编译通过 static void Main(string[] args){ event MyDelegate myEvent2; //编译出错 } }
事件只能在类内调用
public delegate void MyDelegate(); class DelegateClass{ public event MyDelegate myEvent; public void EventFunc(){ myEvent(); //编译通过 } } class Test{ static void Main(string[] args){ DelegateClass delegateClass = new DelegateClass(); delegateClass.myEvent(); //编译出错 } }
发布-订阅模式
事件使用发布-订阅(publisher-subscriber)模型,在这个模型中,发布器(publisher)为包含事件的类,订阅器(subscriber)为接收事件的类,调度中心(Topic)为事件。
以下通过一个简单的案例来更好的理解这种模式。
using System;
using System.Collections.Generic;
using System.Text;
namespace CSharp事件
{
//发布器
class Publisher
{
private int value;
public Publisher(int v)
{
value = v;
}
//声明委托以及事件
public delegate void MyDelegate();
public event MyDelegate changeValue;
public void SetValue(int v)
{
int formerValue = value;
value = v;
Console.WriteLine("Set is complete!");
//当value值改变时,调用事件
if (changeValue != null && formerValue != value)
changeValue();
}
}
//订阅器
class Subscriber
{
public void Print()
{
Console.WriteLine("The value has been changed!");
}
}
class MainClass
{
static void Main(string[] args)
{
//实例化订阅器并赋value为3
Publisher publisher = new Publisher(3);
Subscriber subscriber = new Subscriber();
//将订阅器中的方法Print注册到发布器的事件中
publisher.changeValue += subscriber.Print;
//从控制台接受一个整数
int v = Convert.ToInt32(Console.ReadLine());
//设置订阅器对象的value值
publisher.SetValue(v);
}
}
}
当输入的值为3(与初始化value值相同),输出结果如下:
当输入值为5(与初始化value值不同),输出结果如下: