delegate vs. event(转自LTP.NET知识库)
首先说明,event其实也是一种delegate,为了区分,我们称一般的delegate为“plain delegate”。
写代码的过程中,经常会在delegate和event之间进行选择,以前也没仔细思考选择的原因,今天终于忍不住花了半天时间仔细琢磨了一下……好了,直接拿代码说话吧:
分析:
写代码的过程中,经常会在delegate和event之间进行选择,以前也没仔细思考选择的原因,今天终于忍不住花了半天时间仔细琢磨了一下……好了,直接拿代码说话吧:
1
using System;
2
3
namespace EventAndDelegate
4
{
5
public delegate void TestDelegate(string s);
6
7
public interface ITest {
8
// 【区别】 1. event可以用在interface中,而plain delegate不可以(因为它是field)
9
event TestDelegate TestE; // Passed
10
TestDelegate TestD; // Error: Interfaces cannot contain fields
11
}
12
13
public class Parent {
14
public event TestDelegate TestE;
15
public TestDelegate TestD;
16
17
protected void RaiseTestE(string s)
18
{
19
TestE(s); // The event 'EventAndDelegate.Parent.TestE' can only
20
// be used from within the type 'EventAndDelegate.Parent'
21
}
22
}
23
24
public class Child : Parent {
25
void ChildFunc()
26
{
27
// 【区别】 2. event不允许在声明它的class之外(即使是子类)被调用(除此之外只能用于+=或-=),而plain delegate则允许
28
TestD("OK"); // Passed
29
TestE("Failure"); // Error: The event 'EventAndDelegate.Parent.TestE' can only appear on
30
// the left hand side of += or -= (except when used from within
31
// the type 'EventAndDelegate.Parent')
32
33
// 【补充】 在子类中要触发父类声明的event,通常的做法是在父类中声明一个protected的Raisexxx方法供子类调用
34
RaiseTestE("OK"); // The class 'EventAndDelegate.Child' can only call the
35
// 'EventAndDelegate.ParentRaiseTestE' method to raise the event
36
// 'EventAndDelegate.Parent.TestE'
37
38
// 【区别】 同2#
39
object o1 = TestD.Target;
40
object o2 = TestE.Target; // The class 'EventAndDelegate.Child' can only call the
41
// 'EventAndDelegate.ParentRaiseTestE' method to raise the event
42
// 'EventAndDelegate.Parent.TestE'
43
44
// 【区别】 同2#
45
TestD.DynamicInvoke("OK");
46
TestE.DynamicInvoke("OK"); // The class 'EventAndDelegate.Child' can only call the
47
// 'EventAndDelegate.ParentRaiseTestE' method to raise the event
48
// 'EventAndDelegate.Parent.TestE'
49
}
50
}
51
52
class Other
53
{
54
static void Main(string[] args)
55
{
56
Parent p = new Parent();
57
58
p.TestD += new TestDelegate(p_Test1); // Passed
59
p.TestE += new TestDelegate(p_Test1); // Passed
60
61
// 【区别】 3. event不允许使用赋值运算符,而plain delegate则允许。
62
// 注意,对plain delegate,使用赋值运算符意味着进行了一次替换操作!
63
p.TestD = new TestDelegate(p_Test2); // Passed
64
p.TestE = new TestDelegate(p_Test2); // Error: The event 'EventAndDelegate.Parent.TestE' can only appear on
65
// the left hand side of += or -= (except when used from within
66
// the type 'EventAndDelegate.Parent')
67
68
// 【区别】 同2#
69
p.TestD("OK"); // Passed
70
p.TestE("Failure"); // Error: The event 'EventAndDelegate.Parent.TestE' can only appear on
71
// the left hand side of += or -= (except when used from within
72
// the type 'EventAndDelegate.Parent')
73
}
74
75
static void p_Test1(string s)
76
{
77
Console.WriteLine("p_Test1: " + s);
78
}
79
80
static void p_Test2(string s)
81
{
82
Console.WriteLine("p_Test2: " + s);
83
}
84
}
85
}
86
using System;2

3
namespace EventAndDelegate4
{5
public delegate void TestDelegate(string s);6

7
public interface ITest {8
// 【区别】 1. event可以用在interface中,而plain delegate不可以(因为它是field)9
event TestDelegate TestE; // Passed10
TestDelegate TestD; // Error: Interfaces cannot contain fields11
}12

13
public class Parent {14
public event TestDelegate TestE;15
public TestDelegate TestD;16

17
protected void RaiseTestE(string s)18
{19
TestE(s); // The event 'EventAndDelegate.Parent.TestE' can only20
// be used from within the type 'EventAndDelegate.Parent'21
}22
}23

24
public class Child : Parent {25
void ChildFunc()26
{27
// 【区别】 2. event不允许在声明它的class之外(即使是子类)被调用(除此之外只能用于+=或-=),而plain delegate则允许28
TestD("OK"); // Passed29
TestE("Failure"); // Error: The event 'EventAndDelegate.Parent.TestE' can only appear on30
// the left hand side of += or -= (except when used from within31
// the type 'EventAndDelegate.Parent')32

33
// 【补充】 在子类中要触发父类声明的event,通常的做法是在父类中声明一个protected的Raisexxx方法供子类调用34
RaiseTestE("OK"); // The class 'EventAndDelegate.Child' can only call the35
// 'EventAndDelegate.ParentRaiseTestE' method to raise the event36
// 'EventAndDelegate.Parent.TestE'37

38
// 【区别】 同2#39
object o1 = TestD.Target;40
object o2 = TestE.Target; // The class 'EventAndDelegate.Child' can only call the41
// 'EventAndDelegate.ParentRaiseTestE' method to raise the event42
// 'EventAndDelegate.Parent.TestE'43

44
// 【区别】 同2#45
TestD.DynamicInvoke("OK");46
TestE.DynamicInvoke("OK"); // The class 'EventAndDelegate.Child' can only call the47
// 'EventAndDelegate.ParentRaiseTestE' method to raise the event48
// 'EventAndDelegate.Parent.TestE'49
}50
}51

52
class Other53
{54
static void Main(string[] args)55
{56
Parent p = new Parent();57

58
p.TestD += new TestDelegate(p_Test1); // Passed59
p.TestE += new TestDelegate(p_Test1); // Passed60

61
// 【区别】 3. event不允许使用赋值运算符,而plain delegate则允许。62
// 注意,对plain delegate,使用赋值运算符意味着进行了一次替换操作!63
p.TestD = new TestDelegate(p_Test2); // Passed64
p.TestE = new TestDelegate(p_Test2); // Error: The event 'EventAndDelegate.Parent.TestE' can only appear on65
// the left hand side of += or -= (except when used from within66
// the type 'EventAndDelegate.Parent')67

68
// 【区别】 同2#69
p.TestD("OK"); // Passed70
p.TestE("Failure"); // Error: The event 'EventAndDelegate.Parent.TestE' can only appear on71
// the left hand side of += or -= (except when used from within72
// the type 'EventAndDelegate.Parent')73
}74

75
static void p_Test1(string s)76
{77
Console.WriteLine("p_Test1: " + s);78
}79

80
static void p_Test2(string s)81
{82
Console.WriteLine("p_Test2: " + s);83
}84
}85
}86

分析:
- plain delegate与event的关系类似于field与Property(实事上前者就是field,或者我们可以把event看成是一种特殊的Property)
- 正是由于1#,在使用上,plain delegate几乎没有任何限制,而event则有严格的限制(只能用在+=和-=的左边)
结论:
- event更面向对象一些。
- 当我们需要灵活时,直接使用plain delegate;反之,需要严格的控制时,使用event。
- 由于event不能使用赋值运算符,因此有时我们要求一个事件在任何时刻只能有一个响应方法时,我们使用plain delegate更为方便。
- ……(大家补充)


浙公网安备 33010602011771号