我目前正在尝试学习一些C#中的事件处理,并且目前正在测试东西,并且已经创建了这个小的测试程序。
public class Message : EventArgs {
public string message { get; set; }
public Message(String message){
this.message = message;
}
}
public class Component {
public event EventHandler<Message> onComponentEvent;
public string uuid;
public Component () {
Guid g = Guid.NewGuid();
uuid = g.ToString();
}
public void update () {
Task.Factory.StartNew (() => componentEvent (uuid));
}
private void componentEvent (string message) {
onComponentEvent?.Invoke(this, new Message(message));
}
}
public class Entity {
List<Component> components;
public EventHandler<Message> EntityEvent;
public Entity () {
components = new List<Component>();
}
public void addComponent () {
var c = new Component();
c.onComponentEvent += ComponentEvents;
this.components.Add (c);
}
public void update () {
System.Console.WriteLine("I am an entity and I am updating");
foreach (Component c in this.components) {
c.update ();
}
}
private void ToManagerEvent (String message) {
EntityEvent?.Invoke(this, new Message(message));
}
private void ComponentEvents (object source, Message e) {
Task.Factory.StartNew ( () => ToManagerEvent ( e.message ));
}
}
public class Manager {
List<Entity> entities;
public EventHandler<Message> ManagerEvent;
public Manager () {
this.entities = new List<Entity>();
}
public void addEntity (Entity e) {
e.EntityEvent += EntityEvents;
this.entities.Add(e);
}
public void update () {
foreach ( Entity e in entities ) {
e.update ();
}
}
private void ToGameManagerEvent (Message message) {
ManagerEvent?.Invoke(this, message);
}
private void EntityEvents (object source, Message e) {
System.Console.WriteLine(e.message);
Task.Factory.StartNew ( () => ToGameManagerEvent (e));
}
}
public class GameManager {
ConcurrentQueue<Entity> queue;
Manager manager;
public GameManager () {
this.queue = new ConcurrentQueue<Entity>();
this.manager = new Manager();
this.manager.ManagerEvent += ManagerEvents;
Entity e1 = new Entity();
e1.addComponent();
this.manager.addEntity(e1);
}
public void update () {
while (this.queue.TryDequeue(out Entity en)){
manager.addEntity(en);
}
System.Console.WriteLine("begin update");
manager.update();
}
private void ManagerEvents (object source, Message e) {
queue.Enqueue (new Entity());
}
}
class Program
{
static void Main(string[] args)
{
GameManager gm = new GameManager();
//1
gm.update();
System.Threading.Thread.Sleep(500);
//2
gm.update();
System.Threading.Thread.Sleep(500);
//4
gm.update();
System.Threading.Thread.Sleep(500);
//8
gm.update();
System.Threading.Thread.Sleep(500);
}
}
简而言之,该程序应该有一个更新循环,在该循环中,每次更新都会触发一个事件,该事件从Component -> Entity -> Manager -> GameManager
起泡。然后,Gamemanager
然后在队列中添加新的Entity
,并尝试在每个管理器更新之前出队并将其添加到managers
entity
列表中。
预期行为=>每次更新都会使实体数量翻倍。发生的行为=>只有一个组件会触发一个事件,该事件被冒泡,每次更新只会导致1个新实体。
因此,同时订阅多个发布者会出现问题吗?我认为对此我有误解,因此非常欢迎提出任何指向我做错事情的指示。
您在代码中的问题是这样:
private void ManagerEvents (object source, Message e) {
queue.Enqueue (new Entity());
}
您只是添加一个普通的Entity
。没有组件触发事件。
您应该做的是这:
private void ManagerEvents (object source, Message e) {
Entity e1 = new Entity();
e1.addComponent();
queue.Enqueue (e1);
}
现在您获得了我认为您期望的输出:
开始更新我是实体,我正在更新fdc40694-fcf9-4f49-b2b1-29ff9735214f开始更新我是实体,我正在更新我是实体,我正在更新fdc40694-fcf9-4f49-b2b1-29ff9735214fa05b42fa-5c77-4d4c-a59c-b7f85bdcf1cc开始更新我是实体,我正在更新我是实体,我正在更新我是实体,我正在更新我是实体,我正在更新fdc40694-fcf9-4f49-b2b1-29ff9735214fa05b42fa-5c77-4d4c-a59c-b7f85bdcf1cc6dfd20ed-72c5-4fde-b41f-0fa250d3b760d343a7b3-a7e1-4785-8bd7-1df3cb947255开始更新我是实体,我正在更新我是实体,我正在更新我是实体,我正在更新我是实体,我正在更新我是实体,我正在更新a05b42fa-5c77-4d4c-a59c-b7f85bdcf1ccfdc40694-fcf9-4f49-b2b1-29ff9735214f1b02458c-e015-4cb8-81d6-26e8f94821fcd343a7b3-a7e1-4785-8bd7-1df3cb9472556dfd20ed-72c5-4fde-b41f-0fa250d3b760我是实体,我正在更新我是实体,我正在更新我是实体,我正在更新1b06f9fd-1f94-4db0-a6ff-7574c833af9c2cb02ff4-eb18-4024-92cf-1d098bde476a5b674091-2f8f-4613-9aba-274aee938e94
我还对您的代码进行了一些更新,以使其更符合常规命名约定等。
尝试一下:
public class MessageEventArgs : EventArgs
{
public string Message { get; private set; }
public MessageEventArgs(string message)
{
this.Message = message;
}
}
public class Component
{
public event EventHandler<MessageEventArgs> ComponentEvent;
public string Uuid { get; private set; }
public Component()
{
this.Uuid = Guid.NewGuid().ToString();
}
public async Task UpdateAsync()
{
Console.WriteLine(" Component.UpdateAsync() - Begin");
await this.OnComponentEventAsync(this.Uuid);
Console.WriteLine(" Component.UpdateAsync() - End");
}
protected virtual void OnComponentEvent(string message)
{
this.ComponentEvent?.Invoke(this, new MessageEventArgs(message));
}
protected virtual Task OnComponentEventAsync(string message)
{
return Task.Factory.StartNew(() => this.OnComponentEvent(message));
}
}
public class Entity
{
private List<Component> _components;
public EventHandler<MessageEventArgs> EntityEvent;
public Entity()
{
_components = new List<Component>();
}
public void AddComponent()
{
var c = new Component();
c.ComponentEvent += this.ComponentEvent;
_components.Add(c);
}
public async Task UpdateAsync()
{
Console.WriteLine(" Entity.UpdateAsync() - Begin");
foreach (Component c in _components)
{
await c.UpdateAsync();
}
Console.WriteLine(" Entity.UpdateAsync() - End");
}
protected virtual void OnEntityEvent(string message)
{
this.EntityEvent?.Invoke(this, new MessageEventArgs(message));
}
protected virtual Task OnEntityEventAsync(string message)
{
return Task.Factory.StartNew(() => this.OnEntityEvent(message));
}
private async void ComponentEvent(object source, MessageEventArgs e)
{
await this.OnEntityEventAsync(e.Message);
}
}
public class Manager
{
private List<Entity> _entities;
public event EventHandler<MessageEventArgs> ManagerEvent;
public Manager()
{
_entities = new List<Entity>();
}
public void AddEntity(Entity e)
{
e.EntityEvent += this.EntityEvent;
_entities.Add(e);
}
public async Task UpdateAsync()
{
Console.WriteLine(" Manager.UpdateAsync() - Begin");
foreach (var e in _entities)
{
await e.UpdateAsync();
}
Console.WriteLine(" Manager.UpdateAsync() - End");
}
protected virtual void OnManagerEvent(string message)
{
this.ManagerEvent?.Invoke(this, new MessageEventArgs(message));
}
protected virtual Task OnManagerEventAsync(string message)
{
return Task.Factory.StartNew(() => this.OnManagerEvent(message));
}
private async void EntityEvent(object source, MessageEventArgs e)
{
System.Console.WriteLine(e.Message);
await this.OnManagerEventAsync(e.Message);
}
}
public class GameManager
{
private ConcurrentQueue<Entity> _queue = new ConcurrentQueue<Entity>();
private Manager _manager = new Manager();
public GameManager()
{
_manager.ManagerEvent += this.ManagerEvent;
var entity = new Entity();
entity.AddComponent();
_manager.AddEntity(entity);
}
public async Task UpdateAsync()
{
Console.WriteLine("");
Console.WriteLine("GameManager.UpdateAsync() - Begin");
while (_queue.TryDequeue(out var entity))
{
_manager.AddEntity(entity);
}
await _manager.UpdateAsync();
Console.WriteLine("GameManager.UpdateAsync() - End");
Console.WriteLine("");
}
private void ManagerEvent(object source, MessageEventArgs e)
{
var entity = new Entity();
entity.AddComponent();
_queue.Enqueue(entity);
}
}
class Program
{
static async Task Main(string[] args)
{
var gm = new GameManager();
//1
await gm.UpdateAsync();
await Task.Delay(TimeSpan.FromSeconds(0.5));
//2
await gm.UpdateAsync();
await Task.Delay(TimeSpan.FromSeconds(0.5));
//4
await gm.UpdateAsync();
await Task.Delay(TimeSpan.FromSeconds(0.5));
//8
await gm.UpdateAsync();
await Task.Delay(TimeSpan.FromSeconds(0.5));
}
}