- c - 在位数组中找到第一个零
- linux - Unix 显示有关匹配两种模式之一的文件的信息
- 正则表达式替换多个文件
- linux - 隐藏来自 xtrace 的命令
我至少阅读了十几篇关于事件的文章和 SO 线程,并弄清楚了基本的想法,但我对如何以正确的方式做到这一点有些困惑。似乎至少有两种常见的事件编写方法,一种比另一种更值得推荐。
我看到很多 Material 中作者跳过了部分过程,并假设出于某种原因您会知道这一点。还有很多教程,如“MyEventExample”和“SomeProcessGoesHere”,这使得理解整个示例变得更加困难。很多例子都在教你如何做某事,但最后却声明你在现实中当然永远不会那样做——但它们并没有提供你会 去做。
最后,使用事件的场景的每个组件的命名约定似乎无处不在。我很难弄清楚某些概念在何处应用,因为每个人都以不同的方式命名它的每一部分。
所以这就是我所追求的:我在游戏中有一个简单的情况,它会利用事件。我希望有人参与并编写事件接线,演示推荐的方法以及最常见的命名和结构约定。我知道要求为我编写代码是一种糟糕的形式,但我确实在寻找编写代码的方式,以便我可以自信地开始自己编写代码。
请忽略这是否是一个好的游戏设计,甚至是否适合举办事件。我只是对如何正确编写事件内容感兴趣,这是我的示例空间。
//In my game I have a number of entities which can 'talk' to the player.
//An NPC can greet them, a zone might 'greet' them by displaying "Cityville"
//when they enter it, their inventory might tell them they're out of space,
//and so on. Everything would pass a Message object to a Messenger object,
//which would then deliver the messages as it saw fit.
public class Messenger
{
private Queue<Message> _messages = new Queue<Message>();;
private Stack<Message> _archive = new Stack<Message>();;
public IEnumerable<Message> Messages { get { return _messages.AsEnumerable(); } }
public IEnumerable<Message> Archive { get { return _archive.AsEnumerable(); } }
public void Add(Message message)
{
_messages.Enqueue(message);
}
public void Deliver()
{
Message msg = _messages.Dequeue();
_archive.Push(msg);
//Here's where I'd broadcast to any subsystem listening
//that the message was delivered
//Event args should be (_archive.Peek(), DateTime.Now);
}
public event MessageDeliveryEvent Delivery;
protected virtual void OnDelivery(MessageHandlerDeliveryEventArgs e)
{
if (this.Delivery != null) { this.Delivery(this, e); }
}
}
//Okay, here's my delegate declared outside any class. One tutorial suggested
//putting it in the same file as the event arguments class so it would be
//easier to find, which sounds reasonable to me, but I dunno.
public delegate void MessageDeliveryEvent(object sender, MessageHandlerDeliveryEventArgs e);
//I've seen examples where they don't even write an event arguments class.
//I think you could probably just pass the same stuff directly, but the
//separate class sounds like a good idea, more flexible if things change.
public class MessageHandlerDeliveryEventArgs : EventArgs
{
private readonly Message _message;
private readonly DateTime _delivered;
public MessageHandlerDeliveryEventArgs(Message message, DateTime delivered)
{
_message = message;
_delivered = delivered;
}
public Message Message { get { return _message; } }
public DateTime DeliveryDateTime { get { return _delivered; } }
}
//So in the UI layer I'd have things like a ChatBox which would be a
//scrolling list of everything said to the player. There would also be a
//GeneralInfoBox control that displayed things like what zone you just
//entered, or that your inventory is full. Both would listen to the
//Messenger object for a delivery event, and then check the Message object
//associated with that event to see if they needed to handle the display
//of that message.
public class ChatBox
{
//OMG there's a new message, lemme see if I should display it
private void TheThingThatListensToMessengerEvents(Message message, DateTime datetime)
{
if Message.Type == MessageType.Chat { Print(datetime.ToString() + ": " + message.Text); }
}
public string Print(string text) {}
}
public class GeneralInfoBox
{
//OMG there's a new message, lemme see if I should display it
private void TheThingThatListensToMessengerEvents(Message message)
{
if Message.Type == MessageType.General { Print(message.Text); }
}
public string Print(string text) {}
}
如果我能澄清任何事情,请告诉我。如果有一个非常好的教程我显然错过了,请随时指出我。提前致谢。
这是我的示例,其中包含事件。也许它会帮助像我一样思考的其他人(上帝帮助他们)想象它。
public class MessageHandler
{
private Queue<Message> _messages = new Queue<Message>();
private Stack<Message> _archive = new Stack<Message>();
public MessageHandler() { }
public IEnumerable<Message> Messages { get { return _messages.AsEnumerable(); } }
public IEnumerable<Message> Archive { get { return _archive.AsEnumerable(); } }
public void Add(Message message)
{
_messages.Enqueue(message);
}
public void Deliver()
{
Message msg = _messages.Dequeue();
_archive.Push(msg);
//Call the method which broadcasts the event
OnDelivery(new MessageDeliveryEventArgs(_archive.Peek(), DateTime.Now));
}
//The event
public event EventHandler<MessageDeliveryEventArgs> Delivery;
//The method which broadcasts the event
protected virtual void OnDelivery(MessageDeliveryEventArgs messageDeliveryEventArgs)
{
EventHandler<MessageDeliveryEventArgs> handler = Delivery;
if (handler != null) { handler(this, messageDeliveryEventArgs); }
}
}
//The event arguments class for the event of interest. Carries information about this kind of event
public class MessageDeliveryEventArgs : EventArgs
{
private readonly Message _message;
private readonly DateTime _delivered;
public MessageDeliveryEventArgs(Message message, DateTime delivered)
{
_message = message;
_delivered = delivered;
}
public Message Message { get { return _message; } }
public DateTime DeliveryDateTime { get { return _delivered; } }
}
//A UI control which listens for an event in a Messenger object
public class ChatBox
{
//Specify the instance of the Messenger class to whose event(s) we plan to subscribe
public ChatBox(MessageHandler messenger)
{
//Subscribe this control's OnDelivery method to the Delivery event of the specified instance of Messenger
messenger.Delivery += this.OnDelivery;
}
//The method which we intend to subscribe to the Delivery event of an instance of Messenger
private void OnDelivery(object sender, MessageDeliveryEventArgs e)
{
if (e.Message.Format == MessageFormat.Local)
{
Print(String.Format("{0}: {1}", e.DeliveryDateTime, e.Message.Text));
}
}
private void Print(string text) { }
}
最佳答案
这是设置标准 .Net 事件所遵循的典型约定的示例:
using System;
namespace ObserverExample
{
class Program
{
static void Main(string[] args)
{
var subject = new Subject();
var observer = new Observer();
observer.Observe(subject);
subject.SomeAction();
Console.ReadLine();
}
}
public class Subject
{
public event EventHandler<TopicEventArgs> TopicHappening;
public void SomeAction()
{
OnTopicHappening(new TopicEventArgs("Hello, observers!"));
}
protected virtual void OnTopicHappening(TopicEventArgs topicEventArgs)
{
EventHandler<TopicEventArgs> handler = TopicHappening;
if (handler != null)
handler(this, topicEventArgs);
}
}
public class TopicEventArgs : EventArgs
{
public TopicEventArgs(string message)
{
Message = message;
}
public string Message { get; private set; }
}
public class Observer
{
public void Observe(Subject subject)
{
subject.TopicHappening += subject_TopicHappening;
}
void subject_TopicHappening(object sender, TopicEventArgs e)
{
Console.WriteLine(e.Message);
}
}
}
此示例中涉及的三个主要类是 Subject
, Observer
, 和 TopicEventArgs
. Program
类仅用于为示例提供驱动程序。
首先查看 Program.Main() 方法,首先实例化 Subject(将引发事件的对象)和 Observer(将订阅引发的事件的对象)的实例。接下来,向观察者传递一个主题实例,使其有机会订阅任何所需的事件。最后,调用主体的 SomeAction() 方法,这会引发事件。
查看主题,我们看到名为 TopicHappening 的事件 EventHandler<TopicEventArgs>
被公开宣布。 EventHandler 类型是在 .Net 2.0 中引入的,它允许在不必显式定义委托(delegate)类型的情况下声明事件。 Subject 类也有两个方法,SomeAction()
和 OnTopicHappening()
.方法SomeAction()
表示应用程序中的点,Subject 执行一些它想要通知世界(即“任何观察者”)的任务。方法OnTopicHappening(TopicEventArgs)
方法提供类中将引发事件的逻辑点。首先,请注意它遵循 On[事件名称] 的命名约定。虽然此方法可以命名为任何名称,但此模式已按惯例广泛采用。其次,请注意它被定义为采用 TopicEventArgs 类型的单个参数。这也遵循标准约定,目的是在引发事件的逻辑点(在 SomeAction() 方法中)而不是从引发事件的物理点来决定引发哪些事件参数。第三,注意它被声明为 protected 虚拟。通常遵循此模式以允许任何扩展 Subject 的类覆盖引发 TopicHappening 事件时究竟发生了什么。在 OnTopicHappening() 方法中,TopicHappening 事件在检查是否为 null 并被调用之前被分配给一个单独的变量。这是为了避免可能的竞争条件,即事件可能在检查 null 之后但在调用事件之前被另一个线程(即所有观察者取消订阅)清除。
查看 TopicEventArgs 类,这代表我们的主题提出的事件主题。当主题需要将信息与引发的事件相关联时,通常会创建自定义 EventArgs 类。对于只希望发送没有任何关联参数的信号事件的主题,应使用基 EventArgs.Empty 类。
最后,Observer 类定义将从 Subject 接收事件通知的对象。在此示例中,Observer 类公开了一个 Observe() 方法,作为接收对 Subject 实例的引用的一种方式。在该方法中,一个名为 subject_TopicHappening 的私有(private)事件处理程序方法被分配给主题上的 TopicHappening 事件。此名称格式是 Visual Studio 在注册处理事件时键入 += 时自动生成的委托(delegate)的结果。这实质上是将此方法添加到方法集合中,以便在主题引发事件时调用。调用时,私有(private) subject_TopicHappening 方法只是将事件参数中包含的消息写入控制台。
希望这对您有所帮助。
关于c# - 帮助我以正确的方式编写此事件,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/3272042/
我一直在阅读有关汇编函数的内容,但对于是使用进入和退出还是仅使用调用/返回指令来快速执行,我感到很困惑。一种方式快而另一种方式更小吗?例如,在不内联函数的情况下,在汇编中执行此操作的最快(stdcal
我正在处理一个元组列表,如下所示: res = [('stori', 'JJ'), ('man', 'NN'), ('unnatur', 'JJ'), ('feel', 'NN'), ('pig',
最近我一直在做很多网络或 IO 绑定(bind)操作,使用线程有助于加快代码速度。我注意到我一直在一遍又一遍地编写这样的代码: threads = [] for machine, user, data
假设我有一个名为 user_stats 的资源,其中包含用户拥有的帖子、评论、喜欢和关注者的数量。是否有一种 RESTful 方式只询问该统计数据的一部分(即,对于 user_stats/3,请告诉我
我有一个简单的 api,它的工作原理是这样的: 用户创建一个请求 ( POST /requests ) 另一个用户检索所有请求 ( GET /requests ) 然后向请求添加报价 ( POST /
考虑以下 CDK Python 中的示例(对于这个问题,不需要 AWS 知识,这应该对基本上任何构建器模式都有效,我只是在这个示例中使用 CDK,因为我使用这个库遇到了这个问题。): from aws
Scala 中管理对象池的首选方法是什么? 我需要单线程创建和删除大规模对象(不需要同步)。在 C++ 中,我使用了静态对象数组。 在 Scala 中处理它的惯用和有效方法是什么? 最佳答案 我会把它
我有一个带有一些内置方法的类。这是该类的抽象示例: class Foo: def __init__(self): self.a = 0 self.b = 0
返回和检查方法执行的 Pythonic 方式 我目前在 python 代码中使用 golang 编码风格,决定移动 pythonic 方式 例子: import sys from typing imp
我正在开发一个 RESTful API。其中一个 URL 允许调用者通过 id 请求特定人员的记录。 返回该 id 不存在的记录的常规值是什么?服务器是否应该发回一个空对象或者一个 404,或者其他什
我正在使用 pathlib.Path() 检查文件是否存在,并使用 rasterio 将其作为图像打开. filename = pathlib.Path("./my_file-name.tif") 但
我正在寻找一种 Pythonic 方式来从列表和字典创建嵌套字典。以下两个语句产生相同的结果: a = [3, 4] b = {'a': 1, 'b': 2} c = dict(zip(b, a))
我有一个正在操裁剪理设备的脚本。设备有时会发生物理故障,当它发生时,我想重置设备并继续执行脚本。我有这个: while True: do_device_control() device
做组合别名的最pythonic和正确的方法是什么? 这是一个假设的场景: class House: def cleanup(self, arg1, arg2, kwarg1=False):
我正在开发一个小型客户端服务器程序来收集订单。我想以“REST(ful)方式”来做到这一点。 我想做的是: 收集所有订单行(产品和数量)并将完整订单发送到服务器 目前我看到有两种选择: 将每个订单行发
我知道在 Groovy 中您可以使用字符串调用类/对象上的方法。例如: Foo."get"(1) /* or */ String meth = "get" Foo."$meth"(1) 有没有办法
在 ECMAScript6 中,您可以使用扩展运算符来解构这样的对象 const {a, ...rest} = obj; 它将 obj 浅拷贝到 rest,不带属性 a。 有没有一种干净的方法可以在
我有几个函数返回数字或None。我希望我的包装函数返回第一个不是 None 的结果。除了下面的方法之外,还有其他方法吗? def func1(): return None def func2(
假设我想设计一个 REST api 来讨论歌曲、专辑和艺术家(实际上我就是这样做的,就像我之前的 1312414 个人一样)。 歌曲资源始终与其所属专辑相关联。相反,专辑资源与其包含的所有歌曲相关联。
这是我认为必须经常出现的问题,但我一直无法找到一个好的解决方案。假设我有一个函数,它可以作为参数传递一个开放资源(如文件或数据库连接对象),或者需要自己创建一个。如果函数需要自己打开文件,最佳实践通常
我是一名优秀的程序员,十分优秀!