前面讲了委托,现在说一下事件
先看下面的代码:在多数时候,委托是在两个或更多个类和对象间发生的,大多数时候显得有点绕。
delegate void dlgt(string s); //定义一个输入string无返回值的委托
class dlmng
{
public dlgt dl1; //类dlmng中声明一个dlgt委托类型的变量,将以此变量接收另一个类给指定的方法
public void methodA(string str)
{
this.dl1(str); //调用委托变量
}
}
class Program
{
static void Main(string[] args)
{
dlmng dlobj = new dlmng(); //实例一个dlmng类对象
dlobj.dl1 = s => Console.WriteLine(s); //类dlnmng对象的委托变量赋值一个方法
dlobj.methodA("hello"); //调用dlmng类对象的某个方法,在该方法中调用前面指定的委托方法
Console.ReadKey();
}
}
这样定义有个坏处,dl1这个变量对外是公开的,影响类的封装和稳健,我们可以用event来对委托变量进行封装,成为一个“事件”,并给dlgt换个容易理解的事件名字,并把委托声明改一个易理解的事件处理handler名字,然后代码变动比较大
public delegate void numChangedHandler(string s); //定义一个委托numChangedHandler
class dlmng
{
public event numChangedHandler numChanged; //声明一个numChangedHandler型的委托变量(事件),用于注册绑定另一个类的事件处理方法
public void addNum()
{
int i = 0;
while (true)
{
i++;
Thread.Sleep(100);
numChanged(i.ToString()); //调用委托方法
if (i == 20) return;
}
}
}
class Program
{
static void Main(string[] args)
{
dlmng dlobj = new dlmng(); //实例化对象
dlobj.numChanged += s => Console.WriteLine(s); //注册绑定事件方法
dlobj.addNum(); //执行会引发事件的方法
Console.ReadKey();
}
}
综合来说,给一个类定义事件处理程序及使用包括这么6步:
- 定久一个委托 [xx]eventHandler, 后面多用参数形式(object sender, EventArgs e)
- 类A中声明一个委托变量 [xx]eventHandler mmm
- 类A中某个方法调用此委托变量执行委托方法mmm(object sender, EventArgs e)
- 类B中实例类A
- 类B中为类A的委托事件变量注册绑定一个方法
- 类B中执行类A的方法引发类A的事件
- 如果用了上述的参数,需要定义一个EventArgs 类继承自EventArgs
委托定义的返回值通常都为 void
NET 框架中的委托与事件
尽管上面的范例很好地完成了我们想要完成的工作,但是我们不仅疑惑:为什么.NET Framework 中的事件模型和上面的不同?为什么有很多的EventArgs 参数?
在回答上面的问题之前,我们先搞懂 .NET Framework 的编码规范:
-
委托类型的名称都应该以 EventHandler 结束。
-
委托的原型定义:有一个void 返回值,并接受两个输入参数:一个Object 类型,一个EventArgs 类型(或继承自EventArgs)。
-
事件的命名为委托去掉 EventHandler 之后剩余的部分。
-
继承自 EventArgs 的类型应该以EventArgs 结尾。