
[英]C# + Resharper - Events method with underscore - Naming convention
[英]Events - naming convention and style
我正在学习 C# 中的事件/委托。 我能否就我选择的命名/编码风格(取自 Head First C# 一书)征求您的意见?
明天正在教一个朋友这个,并试图想出解释这些概念的最优雅的方式。 (认为理解一门学科的最好方法是尝试教它!)
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");
}
}
nb 代码重构自http://www.codeproject.com/KB/cs/simplesteventexample.aspx
Microsoft 实际上已经编写了大量的命名指南并将其放入 MSDN 库中。 您可以在此处找到这些文章: 命名指南
除了一般的大写准则外,以下是类型成员名称页面上的“事件”:
✔️ 务必用动词或动词短语命名事件。
示例包括
Clicked
、Painting
、DroppedDown
等。✔️ 务必使用前后概念,使用现在时和过去时为事件命名。
例如,在窗口关闭之前引发的关闭事件将称为
Closing
,而在窗口关闭之后引发的事件将称为Closed
。❌ 不要使用“Before”或“After”前缀或后缀来表示前后事件。 使用刚才描述的现在和过去时。
✔️ 务必使用“EventHandler”后缀命名事件处理程序(用作事件类型的委托),如下例所示:
public delegate void ClickedEventHandler(object sender, ClickedEventArgs e);
✔️ 务必在事件处理程序中使用两个名为
sender
和e
参数。sender 参数表示引发事件的对象。 sender 参数通常是
object
类型,即使可以使用更具体的类型。✔️ 务必使用“EventArgs”后缀命名事件参数类。
有几点我想提一下:
Metronome.OnTick 似乎没有正确命名。 从语义上讲,“OnTick”告诉我它会在“Tick”s 时被调用,但这并不是真正发生的事情。 我会称它为“Go”。
然而,通常接受的模型将执行以下操作。 OnTick
是一个引发事件的虚拟方法。 这样,您可以轻松覆盖继承类中的默认行为,并调用基类来引发事件。
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
}
}
}
另外,我知道这是一个简单的示例,但是如果没有附加侦听器,您的代码将抛出Tick(this, EventArgs.Empty)
。 您至少应该包含一个空保护来检查侦听器:
if(Tick != null)
Tick(this, EventArgs.Empty);
但是,如果侦听器在保护和调用之间未注册,则这在多线程环境中仍然容易受到攻击。 最好的办法是首先捕获当前的侦听器并调用它们:
var tickEvent = Tick;
if(tickEvent != null)
tickEvent(this, EventArgs.Empty);
我知道这是一个旧答案,但由于它仍在收集投票,这里是 C# 6 的做事方式。 整个“守卫”概念可以用条件方法调用代替,并且编译器确实在捕获侦听器方面做了正确的事情(TM):
Tick?.Invoke(this, EventArgs.Empty);
我会说一般事件的最佳指南,包括命名约定,在这里。
这是我采用的约定,简要地说:
有趣的是,Microsoft 似乎如何使用 Visual Studio 生成的事件处理程序名称打破自己的命名约定。
我在 .Net 中使用事件多年后发现的一点是,每次调用时都需要重复检查事件的空处理程序。 我还没有看到一段实时代码,它可以执行任何操作,但如果事件为空则不会调用该事件。
我开始做的是在我创建的每个事件上放置一个虚拟处理程序,以节省进行空检查的需要。
public class Metronome
{
public event EventHandler Tick =+ (s,e) => {};
protected virtual void OnTick(EventArgs e)
{
Tick(this, e); // now it's safe to call without the null check.
}
}
看起来不错,除了OnTick
不遵循典型的事件调用模型这一事实。 通常, On[EventName]
会引发事件一次,例如
protected virtual void OnTick(EventArgs e)
{
if(Tick != null) Tick(this, e);
}
考虑创建此方法,并将现有的“ OnTick
”方法重命名为“ StartTick
”,而不是直接从StartTick
调用Tick
,而是从StartTick
方法调用OnTick(EventArgs.Empty)
。
在你的情况下,它可能是:
class Metronome {
event Action Ticked;
internalMethod() {
// bla bla
Ticked();
}
}
以上示例使用以下约定,自我描述;]
事件来源:
class Door {
// case1: property change, pattern: xxxChanged
public event Action<bool> LockStateChanged;
// case2: pure action, pattern: "past verb"
public event Action<bool> Opened;
internalMethodGeneratingEvents() {
// bla bla ...
Opened(true);
LockStateChanged(false);
}
}
顺便提一句。 关键字event
是可选的,但可以区分“事件”和“回调”
事件监听器:
class AlarmManager {
// pattern: NotifyXxx
public NotifyLockStateChanged(bool state) {
// ...
}
// pattern: [as above]
public NotifyOpened(bool opened) {
// OR
public NotifyDoorOpened(bool opened) {
// ...
}
}
并绑定 [代码看起来对人友好]
door.LockStateChanged += alarmManager.NotifyLockStateChanged;
door.Moved += alarmManager.NotifyDoorOpened;
即使手动发送事件也是“人类可读的”。
alarmManager.NotifyDoorOpened(true);
有时更具表现力的可以是“动词 + ing”
dataGenerator.DataWaiting += dataGenerator.NotifyDataWaiting;
无论您选择哪种约定,都要与其保持一致。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.