标签:ica key 静态 实例 结果 表达式 title 返回 asc
C#中的事件还真是有点绕啊,以前用JavaScript的我,理解起来还真是废了好大劲!刚开始还真有点想不明白为什么这么绕,想想和JS的区别,最后终于恍然大悟!
public void add(int n){...};
所以,一个方法不能直接作为其它方法的参数,把一个方法名作为参数,无法指定类型啊,会报错!那我就想啊,既然不能直接传入,那我传入整个对象总可以吧,通过传进来的对象来执行该方法,如下代码:
using System;
namespace MyEventTest
{
public class SomeClass
{
public void Start(int a) { Console.WriteLine("Go:{0}",a); }
}
public class Publisher
{
public void StartEvent(int a, SomeClass sc)
{
if (sc != null)
{
sc.Start(a); //触发回调方法
}
}
}
public class MainClass
{
static void Main()
{
SomeClass some = new SomeClass();
Publisher p = new Publisher();
p.StartEvent(5,some); //Go:5
}
}
}
以上方法确实可以,但C#不完全是这样实现事件的,因为方法的特殊性,C#引入了委托的概念,让委托对象来代表方法作为其它方法的参数;而事件对象,其实就是一个委托对象。下面先介绍一下委托:
对应于以上方法:
public void Start(int a) { Console.WriteLine("Go:{0}",a); }
我们可以定义一个委托类型:
public delegate void MyDel(int a);
MyDel d = some.Start;
注意这里不是 some.Start()
;System.MulticastDelegate
类,它是 System.Delegate
类的子类d = null;
来释放委托对象d;可以对委托对象执行调用,如: d(5);
它将把调用传递给它所引用的方法 some.Start(5);
,对于多播委托,它将按顺序调用它引用的所有方法,但如果其中一个方法抛出异常,且没在方法内部处理,则将会将异常往外抛出,之后的方法调用将终止。
Action< T >
委托表示引用一个返回值类型为void的方法,根据参数个数存在不同的变体版本;如: Action<in T1, in T2>
Func< T >
委托表示引用一个带返回值类型的方法,根据参数个数存在不同的变体版本;如: Func<in T1, out TResult>
1个参数T1和返回值类型TResult。说完了委托的概念,就可以继续讲事件了,因为事件是基于委托的!
.NET Framework 类库中的所有事件均基于 EventHandler
委托,还有泛型版本 EventHandler<EventArgs>
,这个委托是.NET预定义的,不需要我们定义,可以直接用它来实例化一个事件对象,定义如下:
参数object sender对象是对发布者的实例的引用,EventArgs e对象主要用来存储事件数据
public delegate void EventHandler(object sender, EventArgs e); //EventArgs主要用来存储事件数据
public delegate void EventHandler<TEventArgs>(object sender, EventArgs e);
虽然在自定义的类中的事件可基于任何有效委托类型,但是,通常建议使用.NET预定义事件委托类型让事件基于 .NET 标准事件模式
第1步:在发布者类中实例化委托事件,并定义一个实例方法,用来调用委托事件(因为委托事件只能通过定义它的类的实例来调用)。
定义发布者类之前可先定义一个用来存储事件数据的类(它必须派生于 EventArgs
基类),如下:
注意:在方法StartEvent()中,声明了一个变量,来保存事件对象的副本,这样在取得事件对象的副本后,到触发事件时,这段时间内,这个事件副本就不会受其它线程的影响。如:在此期间,其它线程注销了回调方法,那么MyEvent就为null了,这时再触发事件将引发错误。(这就是线程安全的事件,当然还可以通过锁机制,或者为事件对象始终引用一个空方法)
public class MyEventArgs: EventArgs //定义存储事件数据的类
{
public int Current{get;set;}
}
public class Publisher
{
public event EventHandler<MyEventArgs> MyEvent; //第1步:实例化委托事件
public int Sum{get;set;}
public void StartEvent(int a)
{
var EventCopy = MyEvent; //每次都取一个副本
MyEventArgs args = new MyEventArgs();
args.Current = a;
this.Sum += a;
if (EventCopy != null)
{
EventCopy(this,args); //调用事件
}
}
}
第2步:定义订阅者类,在该类中定义和委托事件相匹配的方法(事件触发时,实际要执行的方法)
public class Subscriber
{
public void Dosomething1(object obj, MyEventArgs e)
{
Publisher p = (Publisher)obj;
Console.WriteLine("Meg: Sum = {0}, Current = {1}", p.sum, e.Current);
}
public void Dosomething2(object obj, MyEventArgs e)
{
}
}
第3步:在客户端代码中,在发布者类的实例上为委托事件注册回调方法
public class MainClass
{
static void Main()
{
Publisher p = new Publisher{ Sum = 0 };
Subscriber sub = new Subscriber();
p.MyEvent += sub. Dosomething1; //注册回调方法
p.MyEvent += sub. Dosomething2;
p. StartEvent( 5 ); //调用方法,间接触发事件
p.MyEvent -= sub. Dosomething1; //取消注册
}
}
要点:事件对象其实就是一个委托对象,把事件当委托来看,就比较容易理解了!不要被Event这个单词给蒙蔽了!
介绍完了!下回将介绍C#中的其它一些较难理解的概念!
标签:ica key 静态 实例 结果 表达式 title 返回 asc
原文地址:http://www.cnblogs.com/sjqq/p/6917564.html