Что вы думаете о моей реализации EventAggregator в C#?


Я ищу простой агрегатор событий, чтобы использовать в моем приложении, но я нашел людей становится очень сложным очень быстро, поэтому я думал, что это было достаточно легко написать самому. Это, кажется, работает, но мне интересно, что вы думаете и если вы хотели изменить или что добавить. (Я знаю, что некоторые из них вызывают события в том же потоке, что он был зарегистрирован, но за то, что я планировал я не нуждаюсь в этом.)

public class EventAggregator
{
    private Dictionary<Type, List<WeakReference>> _listeners;

    private object _syncLock;

    public EventAggregator()
    {
        _listeners = new Dictionary<Type, List<WeakReference>>();
        _syncLock = new object();
    }


    public EventAggregator Register<TEvent>(Action<TEvent> eventAction)
    {
        LockAround(() =>
            {
                var listeners = GetListeners(typeof(TEvent));
                listeners.RemoveAll(wr => !wr.IsAlive || (Action<TEvent>)wr.Target == eventAction);
                listeners.Add(new WeakReference(eventAction));
            });
        return this;
    }

    public void Raise<TEvent>(TEvent ev)
    {
        List<WeakReference> targets = null;
        LockAround(() =>
            {
                var listeners = GetListeners(typeof(TEvent));
                targets = listeners
                    .Where(wr => wr.IsAlive)
                    .ToList();
            });

        targets.ForEach(wr => ((Action<TEvent>)wr.Target)(ev));
    }

    private void LockAround(Action action)
    {
        lock (_syncLock)
        {
            action();
        }
    }

    private List<WeakReference> GetListeners(Type type)
    {
        List<WeakReference> result;
        if (_listeners.TryGetValue(type, out result))
        {
            return result;
        }
        result = new List<WeakReference>();
        _listeners[type] = result;
        return result;
    }
}

Вот как я планирую использовать это:

class Program
{
    static void Main(string[] args)
    {
        var ea = new EventAggregator();

        var view = new View(ea);
        var p = new Presenter(ea);

        view.Name = "Name1";
        view.Name = "Name2";

        Console.ReadKey();
    }
}

interface INameChangeEvent
{
    string OldName { get; set; }

    string NewName { get; set; }
}

public class NameChangeEvent : EventArgs, INameChangeEvent
{
    public NameChangeEvent(string oldName, string newName)
    {
        this.OldName = oldName;
        this.NewName = newName;
    }

    public string OldName { get; set; }

    public string NewName { get; set; }
}

class View
{
    private string _name;
    private EventAggregator _ea;

    public View(EventAggregator ea)
    {
        _ea = ea;
    }

    public string Name
    {
        get
        {
            return _name;
        }
        set
        {
            _ea.Raise<INameChangeEvent>(new NameChangeEvent(_name, value));
            _name = value;
        }
    }
}

class Presenter
{
    public Presenter(EventAggregator ea)
    {
        ea.Register<INameChangeEvent>((ev) =>
            Console.WriteLine(string.Format("View name was changed from {0} to {1}",
              ev.OldName, ev.NewName)));
    }
}


4440
10
задан 17 октября 2011 в 09:10 Источник Поделиться
Комментарии
1 ответ

Я не внимательно посмотрел на него, но это мои первоначальные мысли.

Второстепенные моменты

Я бы инициализировать приватные переменные встроенные такой отдельный объект _syncLock = новый объект(); потому что они не зависят от параметров конструктора.

Для удобства чтения я бы не использовать LockAround способ, я бы просто запереть _syncObject.

В GetListeners есть ли основания добавлении список в словарь, когда никаких событий были зарегистрированы для этого типа? Кроме того, можно сделать ее универсальной, потянув в вызова typeof от поднять так _listeners.TryGetValue(typeof на(TEvent), результат).

В Регистре какова цель (действие)водонепроницаемые.Цель == eventAction? Я думаю, что если кто-то хочет зарегистрировать один и тот же обработчик события дважды, то они должны уметь.

Возможно, вы хотите сделать ваше мероприятие агрегатор одноэлементный или использовать фреймворк внедрения зависимостей, чтобы убедиться, существует только один экземпляр в наличии.

Забот

В Поднять следующая строка меня беспокоит целей.По каждому элементу(ТС => ((действие)водонепроницаемые.Цели)(эВ));. Я не уверен, что есть какие-либо гарантия самой слабой ссылки будут живы в этот момент. Вы, вероятно, хотят укрепить ссылку и проверить, что это не null перед вызовом ее.

Наконец

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

5
ответ дан 18 октября 2011 в 08:10 Источник Поделиться