Вопрос по c#, event-handling, events – Справка по дизайну - Полиморфная обработка событий

5

Вопрос о дизайне & # x2013; Полиморфная обработка событий

В настоящее время я пытаюсь уменьшить количество дескрипторов событий в моем текущем проекте. У нас есть несколько систем, которые отправляют данные через USB. В настоящее время у меня есть подпрограмма, чтобы прочитать сообщения и проанализировать начальные данные заголовка, чтобы определить, из какой системы пришло сообщение. Заголовки немного отличаются, поэтому созданные мной EventArgs не совпадают. Затем я уведомляю всех & # x201C; наблюдателей & # x201D; изменения. Итак, сейчас у меня есть следующее:

public enum Sub1Enums : byte
{
    ID1 = 0x01,
    ID2 = 0x02
}

public enum Sub2Enums : ushort
{
    ID1 = 0xFFFE,
    ID2 = 0xFFFF
}

public class MyEvent1Args
{
    public Sub1Enums MessageID;
    public byte[] Data;
    public MyEvent1Args(Sub1Enums sub1Enum, byte[] data)
    {
        MessageID = sub1Enum;
        Data = data;
    }
}

public class MyEvent2Args
{
    public Sub2Enums MessageID;
    public byte[] Data;
    public MyEvent2Args(Sub2Enums sub2Enum, byte[] data)
    {
        MessageID = sub2Enum;
        Data = data;
    }
}

Код Form1

public class Form1
{
    public delegate void TestHandlerCurrentlyDoing(MyEvent1Args eventArgs1);
    public delegate void TestHandlerCurrentlyDoingAlso(MyEvent2Args eventArgs2);

    public event TestHandlerCurrentlyDoing mEventArgs1;
    public event TestHandlerCurrentlyDoingAlso mEventArgs2;

    public Form1()
    {
        mEventArgs1 += new TestHandlerCurrentlyDoing(Form1_mEventArgs1);
        mEventArgs2 += new TestHandlerCurrentlyDoingAlso(Form1_mEventArgs2);
    }

    void Form1_mEventArgs2(MyEvent2Args eventArgs2)
    {
        // Do stuff here
        Sub2Enums mid = my_event2_args.MessageID;
        byte[] data = my_event2_args.Data;
    }

    void Form1_mEventArgs1(MyEvent1Args eventArgs1)
    {
        // Do stuff here
        Sub1Enums mid = my_event1_args.MessageID;
        byte[] data = my_event1_args.Data;
    }

И в алгоритме разбора у меня есть что-то вроде этого в зависимости от того, какое сообщение это:

void ParseStuff()
{
    if (mEventArgs1 != null)
    {
        mEventArgs1(new MyEvent1Args(Sub1Enums.ID1, new byte[] { 0x01 }));
    }
    if (mEventArgs2 != null)
    {
        mEventArgs2(new MyEvent2Args(Sub2Enums.ID2, new byte[] { 0x02 }));
    }
}

Что я действительно хочу сделать, это:

public class Form1
{
    public delegate void TestHandlerDesired(MyEvent1Args eventArgs1);
    public delegate void TestHandlerDesired(MyEvent2Args eventArgs2);

    public event TestHandlerDesired mEventArgs;

    public Form1()
    {
        mEventArgs += new TestHandlerDesired (Form1_mEventArgs1);
        mEventArgs += new TestHandlerDesired (Form1_mEventArgs2);
    }
}

И по причинам двусмысленности мы не можем этого сделать. Итак, мой вопрос, что будет лучшим подходом к этой проблеме?

Похоже, синтаксис C #. Если это так, рассмотрите возможность добавления этой детали в свой вопрос. Кроме того, я думаю, что вы можете пометить его тегом C #, и тогда у вас будет больше просмотров. Ron Klein

Ваш Ответ

5   ответов
0

ии оперативной памяти, сделайте то, что делает Microsoft (в System.ComponentModel.Component), и используйтеEventHandlerList отслеживать все ваши события.Вот статья, которая описывает сохранение использования памяти с EventHandlerList, а такжеВот аналогичная статья, написанная на C #..

Суть в том, что вы можете объявить в своем классе один EventHandlerList (не забудьте его утилизировать) вместе с уникальным ключом:

public class Foo
{
    protected EventHandlerList listEventDelegates = new EventHandlerList();
    static readonly object mouseDownEventKey = new object();

... переопределить свойство события:

public event MouseEventHandler MouseDown {  
   add { listEventDelegates.AddHandler(mouseDownEventKey, value); }
   remove { listEventDelegates.RemoveHandler(mouseDownEventKey, value); }
}

... и предоставить метод RaiseEvent:

protected void RaiseMouseDownEvent(MouseEventArgs e)
{
    MouseEventHandler handler = (MouseEventHandler) base.Events[mouseDownEventKey];
    if (handler != null)
    {
        handler(this, e);
    }
}

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

1

зового класса и сделать следующее:

public class BaseEventArgs : EventArgs
{
    public byte[] Data;
}

public class MyEvent1Args : BaseEventArgs
{ … }
public class MyEvent2Args : BaseEventArgs
{ … }


public delegate void TestHandlerWithInheritance(BaseEventArgs baseEventArgs);

public event TestHandlerWithInheritance mTestHandler;

mTestHandler += new TestHandlerWithInheritance(TestHandlerForEvent1Args);
mTestHandler += new TestHandlerWithInheritance(TestHandlerForEvent2Args);

    void TestHandlerForEvent1Args(BaseEventArgs baseEventArgs)
    {
        MyEvent1Args my_event1_args = (baseEventArgs as MyEvent1Args);
        if (my_event1_args != null)
        {
            // Do stuff here
            Sub1Enums mid = my_event1_args.MessageID;
            byte[] data = my_event1_args.Data;
        }
    }

    void TestHandlerForEvent2Args(BaseEventArgs baseEventArgs)
    {
        MyEvent2Args my_event2_args = (baseEventArgs as MyEvent2Args);
        if (my_event2_args != null)
        {
            // Do stuff here
            Sub2Enums mid = my_event2_args.MessageID;
            byte[] data = my_event2_args.Data;
        }
    }

И в алгоритме разбора у меня есть что-то вроде этого в зависимости от того, какое сообщение это:

        if (mTestHandler!= null)
        {
            mTestHandler (new MyEvent1Args(Sub1Enums.ID1, new byte[] { 0x01 }));
        }
        if (mTestHandler!= null)
        {
            mTestHandler (new MyEvent2Args(Sub2Enums.ID2, new byte[] { 0x02 }));
        }
1

ащения, в частности, шаблон агрегатора событий, если вы еще этого не сделали; Фаулер первый @http://martinfowler.com/eaaDev/EventAggregator.html а затем сообщения от Джереми Миллера, если вам нужно больше идей.

Ура,
Berryl

1

что именно вы хотите достичь здесь):

1. Создайте иерархию EventArgs и возложите на наблюдателей ответственность за фильтрацию материалов, которые им интересны (это то, что вы предложили в своем ответе). Это особенно имеет смысл, если некоторые наблюдатели заинтересованы в нескольких типах сообщений, в идеале описываемых типом базового класса.

2. Не используйте делегаты .Net, просто реализуйте его самостоятельно, чтобы при регистрации делегата он также принимал ожидаемый тип события. Это предполагает, что вы выполнили работу из (1), но вы хотите передать фильтрацию вашему классу, а не наблюдателям

Например. (Непроверенные):

enum MessageType
{
Type1,Type2
}
private Dictionary<MessageType, TestHandlerWithInheritance> handlers;
public void RegisterObserver(MessageType type, TestHandlerWithInheritance handler)
{
  if(!handlers.ContainsKey(type))
  {
    handlers[key] = handler;
  }
  else
  {
    handlers[key] = Delegate.Combine(handlers[key] , handler);
  }
}

И когда приходит новое сообщение, вы запускаете правильный делегат из словаря обработчиков.

3. Реализуйте события так, как это делается в WinForms, чтобы у вас не было основного события для когда-либо выставленного события. Это имеет смысл, если вы ожидаете, что будет больше событий, чем наблюдателей.

Например.:

public event EventHandler SthEvent
{
    add
    {
        base.Events.AddHandler(EVENT_STH, value);
    }
    remove
    {
        base.Events.RemoveHandler(EVENT_STH, value);
    }
}

public void AddHandler(object key, Delegate value)
{
    ListEntry entry = this.Find(key);
    if (entry != null)
    {
        entry.handler = Delegate.Combine(entry.handler, value);
    }
    else
    {
        this.head = new ListEntry(key, value, this.head);
    }
}


public void RemoveHandler(object key, Delegate value)
{
    ListEntry entry = this.Find(key);
    if (entry != null)
    {
        entry.handler = Delegate.Remove(entry.handler, value);
    }
}


private ListEntry Find(object key)
{
    ListEntry head = this.head;
    while (head != null)
    {
        if (head.key == key)
        {
            return head;
        }
        head = head.next;
    }
    return head;
}

private sealed class ListEntry
{
    // Fields
    internal Delegate handler;
    internal object key;
    internal EventHandlerList.ListEntry next;

    // Methods
    public ListEntry(object key, Delegate handler, EventHandlerList.ListEntry next)
    {
        this.next = next;
        this.key = key;
        this.handler = handler;
    }
}

Пожалуйста, дайте мне знать, если вы хотите, чтобы я подробно остановился на любом из ответов.

3

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

Error: User Rate Limit Exceededddj.com/cpp/184403497?pgno=3Error: User Rate Limit Exceeded SwDevMan81
Error: User Rate Limit Exceededaccu.org/index.php/journals/1376Error: User Rate Limit Exceeded
Error: User Rate Limit ExceededDesign pattern for handling multiple message typesError: User Rate Limit Exceeded SwDevMan81

Похожие вопросы