使用事件处理程序处理C#中的多个发布者

问题描述 投票:0回答:1

我目前正在尝试学习一些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个新实体。

因此,同时订阅多个发布者会出现问题吗?我认为对此我有误解,因此非常欢迎提出任何指向我做错事情的指示。

c# .net event-handling publish-subscribe
1个回答
0
投票

您在代码中的问题是这样:

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));
    }
}
© www.soinside.com 2019 - 2024. All rights reserved.