活动 - 命名惯例和风格 [英] Events - naming convention and style
问题描述
明天教一位朋友,而且试图找出解释概念的最优雅的方式。 (认为理解主题的最好办法是尝试教它!)
class Program
{
static void Main()
{
//设置节拍器并确保EventHandler代理已准备好
节拍器节拍器=新的节拍器();
//将metronome_Tick方法连接到EventHandler委托
Listener listener = new Listener(metronome);
metronome.OnTick();
}
}
public class Metronome
{
//一个委托
//所以每当Tick被调用时,运行时调用另一个方法
//这个case Listener.metronome_Tick
public event EventHandler Tick;
public void OnTick()
{
while(true)
{
Thread.Sleep(2000);
//因为使用EventHandler委托,需要包含发送对象和eventargs
//虽然我们不使用它们
Tick(this,EventArgs.Empty);
}
}
}
public class Listener
{
public Listener(Metronome metronome)
{
metronome.Tick + = new EventHandler(metronome_Tick );
}
private void metronome_Tick(object sender,EventArgs e)
{
Console.WriteLine(Heard it);
}
}
n.b。代码从 http://www.codeproject.com/KB/cs/simplesteventexample.aspx重构
有几点我会提到:
节目Metronome.OnTick似乎没有正确的命名。语义上,OnTick告诉我,当它被勾选时,它会被调用,但这不是真的发生了。我会把它称为Go。
然而,通常接受的模式是执行以下操作。 OnTick
是一种引发事件的虚拟方法。这样,您可以轻松地覆盖继承的类中的默认行为,并调用基础来引发事件。
class Metronome
{
public event EventHandler Tick;
protected virtual void OnTick(EventArgs e)
{
//提起Tick事件(见下面的解释)
var tickEvent = Tick;
if(tickEvent!= null)
tickEvent(this,e);
}
public void Go()
{
while(true)
{
Thread.Sleep(2000);
OnTick(EventArgs.Empty); //提起Tick事件
}
}
}
另外,我知道这是一个简单的例子,但是如果没有附加的监听器,你的代码将抛出 Tick(this,EventArgs.Empty) code>。你应该至少包括一个空的警卫来检查听众:
if(Tick!= null)
Tick这个,EventArgs.Empty);
但是,如果监听器在保护和调用之间未注册,则在多线程环境中仍然容易受到攻击。最好的方法是首先捕获当前的听众,并调用它们:
var tickEvent = Tick;
if(tickEvent!= null)
tickEvent(this,EventArgs.Empty);
我知道这是一个古老的答案,但由于它仍在收集upvote,这里是C#做事。整个守卫概念可以用条件方法调用替代,并且编译器在捕获监听器方面确实做了Right Thing(TM):
Tick?.Invoke(this,EventArgs.Empty);
I'm learning about Events / Delegates in C#. Could I ask your opinion on the naming/coding style I've chosen (taken from the Head First C# book)?
Am teaching a friend about this tomorrow, and am trying to come up with the most elegant way of explaining the concepts. (thought the best way to understand a subject is to try and teach it!)
class Program
{
static void Main()
{
// setup the metronome and make sure the EventHandler delegate is ready
Metronome metronome = new Metronome();
// wires up the metronome_Tick method to the EventHandler delegate
Listener listener = new Listener(metronome);
metronome.OnTick();
}
}
public class Metronome
{
// a delegate
// so every time Tick is called, the runtime calls another method
// in this case Listener.metronome_Tick
public event EventHandler Tick;
public void OnTick()
{
while (true)
{
Thread.Sleep(2000);
// because using EventHandler delegate, need to include the sending object and eventargs
// although we are not using them
Tick(this, EventArgs.Empty);
}
}
}
public class Listener
{
public Listener(Metronome metronome)
{
metronome.Tick += new EventHandler(metronome_Tick);
}
private void metronome_Tick(object sender, EventArgs e)
{
Console.WriteLine("Heard it");
}
}
n.b. Code is refactored from http://www.codeproject.com/KB/cs/simplesteventexample.aspx
There are a few points that I would mention:
Metronome.OnTick doesn't seem to be named correctly. Semantically, "OnTick" tells me it will be called when it "Tick"s, but that isn't really what's happening. I would call it "Go" instead.
The typically accepted model, however would be to do the following. OnTick
is a virtual method that raises the event. This way, you can override the default behavior in inherited classes easily, and call the base to raise the event.
class Metronome
{
public event EventHandler Tick;
protected virtual void OnTick(EventArgs e)
{
//Raise the Tick event (see below for an explanation of this)
var tickEvent = Tick;
if(tickEvent != null)
tickEvent(this, e);
}
public void Go()
{
while(true)
{
Thread.Sleep(2000);
OnTick(EventArgs.Empty); //Raises the Tick event
}
}
}
Also, I know this is a simple example, but if there are no listeners attached, your code will throw on Tick(this, EventArgs.Empty)
. You should at least include a null guard to check for listeners:
if(Tick != null)
Tick(this, EventArgs.Empty);
However, this is still vulnerable in a multithreaded environment if the listener is unregistered between the guard and the invocation. The best would be to capture the current listeners first and call them:
var tickEvent = Tick;
if(tickEvent != null)
tickEvent(this, EventArgs.Empty);
I know this is an old answer, but since it's still gathering upvotes, here's the C# 6 way of doing things. The whole "guard" concept can be replaced with a conditional method call and the compiler does indeed do the Right Thing(TM) in regards to capturing the listeners:
Tick?.Invoke(this, EventArgs.Empty);
这篇关于活动 - 命名惯例和风格的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!