我不明白纯委托字段和事件字段之间的区别
本文关键字:字段 事件 区别 之间 明白 | 更新日期: 2023-09-27 18:35:10
代表:我明白。但是当我转到活动时,很多事情我不太了解。我读了书,MSDN和网络上的一些简单示例,它们都具有相同的结构。例如,这里是链接:事件示例
我举第一个例子,作者说这是关于 C# 事件最简单的例子。
这是他的代码:
public class Metronome
{
public event TickHandler Tick;
public EventArgs e = null;
public delegate void TickHandler(Metronome m, EventArgs e);
public void Start()
{
while (true)
{
System.Threading.Thread.Sleep(3000);
if (Tick != null)
{
Tick(this, e);
}
}
}
}
public class Listener
{
public void Subscribe(Metronome m)
{
m.Tick += new Metronome.TickHandler(HeardIt);
}
private void HeardIt(Metronome m, EventArgs e)
{
System.Console.WriteLine("HEARD IT");
}
}
class Test
{
static void Main()
{
Metronome m = new Metronome();
Listener l = new Listener();
l.Subscribe(m);
m.Start();
}
}
您可以注意到行:public event TickHandler Tick
。当我更改为public TickHandler Tick
时,程序仍然运行相同。但是新行我理解,因为它只是一个纯粹的代表。
所以,我的问题是:event
行关键字的真正目的是什么:public event TickHandler Tick
。这非常重要,因为所有的例子总是这样用,但我无法解释为什么。
谢谢:)
委托和事件是相关的概念,但它们不是一回事。术语"代表"往往有两个含义(经常被掩盖):
- 类似于单个方法接口的委托类型。(存在显着差异,但这是一个合理的起点。
- 该类型的实例,通常通过方法组创建,以便在"调用"委托时调用该方法。
事件不是这些。它是一种类型的成员 - 一对添加/删除方法,接受委托订阅或取消订阅事件。使用 foo.SomeEvent += handler;
或 foo.SomeEvent -= handler;
时,将使用 add 和 remove 方法。
这与属性实际上是一对 get/set 方法(或者可能只是两者之一)的方式非常相似。
当您声明类似字段的事件时,如下所示:
public event TickHandler Tick;
编译器将成员添加到您的类中,这些成员有点像这样:
private TickHandler tick;
public event TickHandler
{
add { tick += value; }
remove { tick -= value; }
}
它比这复杂一些,但这是基本思想 - 它是事件的简单实现,就像自动实现的属性一样。从类内部,您可以访问支持字段,而在类外部,您最终总是只使用该事件。
我个人认为很遗憾,类字段事件的声明看起来很像委托类型的字段 - 它会导致在某些答案中发现一些误导性 (IMO) 语句,就好像 event
关键字"修改"字段声明一样 - 而实际上这意味着您正在声明完全不同的内容。我认为如果类似字段的事件看起来更像是自动实现的属性,例如
// Not real C#, but I wish it were...
public event TickHandler Tick { add; remove; }
我有一整篇文章详细介绍了,您可能会发现它很有用。
> event
关键字基本上限制了对delegate
的操作。您不能再使用 =
运算符手动分配它。
您只能从活动中逐个添加(使用 +=
)或删除(使用 -=
)代表。这样做是为了防止某些订阅者"覆盖"其他订阅。
因此,您不能执行以下操作: m.Tick = new Metronome.TickHandler(HeardIt)
" event
" 是一个修饰符。有什么好处?
- 您可以在接口中使用事件
- 只有声明它的类才能调用事件
- 事件公开一个
add
和remove
访问器,您可以重写该访问器并执行自定义操作 - 事件将您限制为分配方法的特定签名
SomeMethod(object source, EventArgs args)
该方法为您提供有关事件的其他信息。
你是对的 - 添加 event
关键字似乎几乎是多余的。但是,作为事件的字段和键入为纯委托的字段之间存在关键区别。使用 event 关键字意味着包含对象外部的对象可以订阅委托,但不能调用委托。删除事件关键字时,外部对象可以订阅并调用委托(可见性允许)。
将侦听器添加到程序时,添加的是事件,而不是委托
查看您的代码 m.勾选 +=
您看到该部分是您请求属性(类型事件),并且正在向其添加具有+=的侦听器。现在,您只能向该 Tick 属性添加 TickHandler 类型,如果您覆盖它,则必须创建自己的与 TickHandler 相同的格式。
就像添加到字符串或整数时一样。
string stringTest = string.Empty;
stringTest += "this works";
stringTest += 4; //this doesn't though
int intTest = 0;
intTest += 1; //works because the type is the same
intTest += "This doesn't work";
Metronome m = new Metronome();
Metronome.TickHandler myTicker = new Metronome.TickHandler(function);
m.Tick += myTicker; //works because it is the right type
m.Tick += 4; //doesn't work... wrong type
m.Tick += "This doesnt work either"; //string type is not TickHandler type
这能澄清一些吗?
据我所知,事件基本上是一个多播委托,但对基本操作有不同的访问规则,可以从定义它们的类内部或外部对委托和事件执行。
这些操作是:
使用 = 运算符进行分配
使用 += 和 -= 运算符添加/删除
使用 () 运算符调用
Operation | delegate | event
------------------+------------+--------
Inside class += / -= | valid | valid
------------------+------------+--------
Inside class = | valid | valid
------------------+------------+--------
Inside class () | valid | valid
------------------+------------+--------
Outside class += / -= | valid | valid
------------------+------------+--------
Outside class = | valid | not valid
------------------+------------+--------
Outside class () | valid | not valid
这为您提供了封装,这始终是良好的OOP风格。
我认为使用委托和事件之间的主要区别在于事件只能由服务器引发(意味着类的作者)
如果现在删除 event
关键字,则可以在Listener
中提高m.Tick(sender,e)
,否则不会。
public class Listener
{
public void Subscribe(Metronome m)
{
m.Tick += new Metronome.TickHandler(HeardIt);
}
private void RaisTick(object sender, EventArgs e)
{
m.Tick(sender,e);
}
private void HeardIt(Metronome m, EventArgs e)
{
System.Console.WriteLine("HEARD IT");
}
}