今天看书分别看了一下这两章,以下仅是自己总结的区别,不全面。
1.事件是特殊的代理,特殊之处在于参数。事件的参数是object 和一个继承自EventArgs的参数。如果参数不符仍然使用event关键字标识,编译器会给出warning。
2.事件使用event关键字标示,编译器将public event EventHandler<EventArgs> NewMail=null;这行代码编译为以下三个结构:
1.private EventHandler<EventArgs> NewMail=null;
2.[MethodImpl(MethodImploptions.Synchronized]
public void add_NewMail(EventHandler<EventArgs> value)
{
NewMail=(EventHandler<EventArgs>(Delegate.Combine(NewMail,Value);
}
3.[MethodImpl(MethodImploptions.Synchronized]
public void remove_NewMail(EventHandler<EventArgs> value)
{
NewMail=(EventHandler<EventArgs>(Delegate.Remove(NewMail,Value);
}
比委托多了两个方法,并且由于这两个方法标示了[MethodImpl(MethodImploptions.Synchronized]属性,就保证了对事件+=,-=时是线程安全的,同一时间只能一个方法执行。当事件为实例成员时,.Net对该实例对象加锁,当事件为静态成员时,对类型对象枷锁,但是这与线程同步指导方针相违背,可能会造成死锁的问题,当实例同时拥有多个事件时,并且+=,-=同时发生时会降低程序的效率。为了解决这个问题,.net提供了显示的add和remove方法,参见以下。不管怎样,代理无法保证线程安全,而事件可以。
3.事件拥有add和remove两个访问器方法并且必须同时拥有,而没有get和set方法。
为了解决上面所说的问题,程序员可以在add和remove方法lock自定义的对象,以使程序更健壮。
4.加了event关键字后该event只允许所属类调用,而普通的代理也可以在外部调用,下列代码:
namespace ConsoleApplication4
{
public class MyEventArgs:EventArgs
{
private int a;
private int b;
public int A
{
get { return a; }
}
public int B
{
get { return b; }
}
public MyEventArgs(int a,int b)
{
this.a = a;
this.b = b;
}
}
public delegate void messagedelegate(object sender, MyEventArgs e);
class Program
{
static void Main(string[] args)
{
Closure c = new Closure();
c.message += c_message;
c.fun();
c.message(c,new MyEventArgs(3,2)); //编译正确,可以直接调用代理函数
}
static void c_message(object sender,MyEventArgs e)
{
Console.Write("c_message)"+e.A+e.B);
}
}
public class Closure
{
public messagedelegate message; //没有使用event关键字标示
public void fun()
{
if (message != null)
{
MyEventArgs e = new MyEventArgs(9, 2);
message(this,e);
}
}
}
}
当public messagedelegate message使用event标示时重新编译,提示错误“Error 1 The event 'ConsoleApplication4.Closure.message' can only appear on the left hand side of += or -= (except when used from within the type 'ConsoleApplication4.Closure') ”,事件只允许在类内部调用。