Обработка нескольких издателей в C# с помощью обработчиков событий - PullRequest
0 голосов
/ 08 апреля 2020

В настоящее время я пытаюсь немного узнать об обработке событий в 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);

    }
}

Короче говоря, эта программа должна иметь обновление l oop, где для каждого обновления компонент запускает событие, которое всплывает с Component -> Entity -> Manager -> GameManager. Где Gamemanager затем добавляет новый Entity в очередь и пытается удалить из очереди и добавить его в список managers entity перед каждым обновлением менеджера.

Ожидаемое поведение => каждое обновление удваивает количество лиц. Поведение происходит => только один компонент запускает всплывающее событие, которое приводит к появлению только 1 нового объекта при каждом обновлении.

Таким образом, существует проблема при одновременной подписке на несколько издателей? Я предполагаю, что в этом есть что-то фундаментальное, я неправильно понимаю, поэтому любые указания на то, что я делаю неправильно, будут очень кстати.

1 Ответ

1 голос
/ 08 апреля 2020

Ваша проблема в вашем коде такова:

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);
}

Теперь вы получите вывод, который, я думаю, ожидал:

begin update
I am an entity and I am updating
fdc40694-fcf9-4f49-b2b1-29ff9735214f
begin update
I am an entity and I am updating
I am an entity and I am updating
fdc40694-fcf9-4f49-b2b1-29ff9735214f
a05b42fa-5c77-4d4c-a59c-b7f85bdcf1cc
begin update
I am an entity and I am updating
I am an entity and I am updating
I am an entity and I am updating
I am an entity and I am updating
fdc40694-fcf9-4f49-b2b1-29ff9735214f
a05b42fa-5c77-4d4c-a59c-b7f85bdcf1cc
6dfd20ed-72c5-4fde-b41f-0fa250d3b760
d343a7b3-a7e1-4785-8bd7-1df3cb947255
begin update
I am an entity and I am updating
I am an entity and I am updating
I am an entity and I am updating
I am an entity and I am updating
I am an entity and I am updating
a05b42fa-5c77-4d4c-a59c-b7f85bdcf1cc
fdc40694-fcf9-4f49-b2b1-29ff9735214f
1b02458c-e015-4cb8-81d6-26e8f94821fc
d343a7b3-a7e1-4785-8bd7-1df3cb947255
6dfd20ed-72c5-4fde-b41f-0fa250d3b760
I am an entity and I am updating
I am an entity and I am updating
I am an entity and I am updating
1b06f9fd-1f94-4db0-a6ff-7574c833af9c
2cb02ff4-eb18-4024-92cf-1d098bde476a
5b674091-2f8f-4613-9aba-274aee938e94

Я также немного обновил ваш код, чтобы сделать его более совместимым с обычными соглашениями об именах, и т. Д. c.

Попробуйте это:

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));
    }
}
...