代表:我明白了。但是当我搬到活动时,很多事情我都不太了解。我在网上读过书,MSDN和一些简单的例子,它们都有相同的结构。例如,以下是链接:Event Example
我采用第一个例子,作者说这是关于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
。这非常重要,因为所有示例总是这样使用,但我无法解释原因。
谢谢:)
答案 0 :(得分:9)
代理和事件是相关的概念,但它们不是相同的东西。 “代表”一词往往有两个含义(经常被掩盖):
事件既不是那些事件。它是一种类型的成员 - 一对添加/删除方法,让代理人订阅或取消订阅该事件。使用foo.SomeEvent += handler;
或foo.SomeEvent -= handler;
时会使用添加和删除方法。
这非常类似于属性实际上是一对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; }
我有一个whole article进入更详细的细节,你会发现它很有用。
答案 1 :(得分:7)
event
关键字基本上限制了delegate
上的操作。
您无法再使用=
运算符手动分配它。
您只能逐个添加(使用+=
)或删除(使用-=
)代表。这样做是为了防止某些订阅者“覆盖”其他订阅。
因此,你无法做到:m.Tick = new Metronome.TickHandler(HeardIt)
答案 2 :(得分:3)
“event
”是一个修饰语。有什么好处?
add
和remove
访问者,您可以覆盖并执行自定义内容SomeMethod(object source, EventArgs args)
的特定签名,该签名为您提供有关该活动的其他信息。答案 3 :(得分:1)
你是对的 - 添加event
关键字似乎几乎是多余的。但是,作为事件的字段和键入纯委托的字段之间存在关键区别。使用event关键字意味着包含对象外部的对象可以订阅委托,但是它们不能调用它。删除event关键字时,外部对象可以订阅并调用委托(可见性允许。)
答案 4 :(得分:1)
向程序添加侦听器时,添加事件,而不是委托
看你的代码m.Tick + =
你看到那个部分就在那里你要求属性(类型事件)并且你正在向它添加一个带有+ =的监听器。现在,您只能向Tick属性添加TickHandler类型,如果您覆盖它,则必须使用与TickHandler相同的格式。
非常类似于添加到字符串或int。
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
是否清除了一些?
答案 5 :(得分:1)
据我所知,一个事件基本上是一个多播委托,但是对于基本操作有不同的访问规则,可以对它们所定义的类内外的委托和事件执行。
操作是:
使用=运算符
进行分配使用+ =和 - =运算符
添加/删除使用()运算符
调用 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风格。 : - )
答案 6 :(得分:0)
我认为使用委托和事件之间的主要区别在于事件只能由服务器引发(意味着类的作者)
如果您现在删除了event
关键字,则可以在m.Tick(sender,e)
中提升Listener
,否则不会。
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");
}
}