Подтвердить что ты не робот

С# делегат против EventHandler

Я хочу отправить предупреждение всем подписчикам, когда произошла ловушка.

Код, который я создал, работает нормально, используя метод делегата myDelegate del.

Мои вопросы:

  1. Я хочу знать, лучше ли использовать EventHandler вместо делегата? Я не уверен, каковы различия между делегатом и EventHandler в моем случае.

  2. notify(trapinfo t), что я сделал здесь, чтобы получить информацию о ловушке. Но, похоже, это не очень хорошая идея. Я прочитал некоторый онлайн-урок по введению объекта делегата; Мне интересно, уместно ли это в моем случае? И как мне это сделать? Какие-либо предложения?

Большое спасибо :)

Мой код:

public class trapinfo
    {
        public string info;
        public string ip;
        public string cause;
    }

    public class trap
    {
        public delegate void myDelegate(trapinfo t);
        public myDelegate del;

        trapinfo info = new trapinfo();

        public void run()
        {
            //While(true) 
            // If a trap occurred, notify the subscriber
            for (; ; )
            {
                Thread.Sleep(500);
                foreach (myDelegate d in del.GetInvocationList())
                {
                    info.cause = "Shut Down";
                    info.ip = "192.168.0.1";
                    info.info = "Test";
                    d.Invoke(info);
                }
            }
        }
    }
    public class machine
    {
        private int _occuredtime=0;

        public trapinfo info = new trapinfo();
        public void notify(trapinfo t)
        {
            ++_occuredtime;
            info.cause = t.cause;
            info.info = t.info;
            info.ip = t.ip;
            getInfo();
        }
        public void subscribe(trap t)
        {
            t.del += new trap.myDelegate(notify);
        }
        public void getInfo()
        {
            Console.WriteLine("<Alert>: cauese/{0}, info/ {1}, ip/{2}, time/{3}",
                info.cause, info.info, info.ip,_occuredtime);
        }
    }
    class Program
    {
        static void Main(string[] args)
        {
            trap t = new trap();
            machine machineA = new machine();
            machineA.subscribe(t);
            t.run();
        }
    }

Обновление 2013-08-12

Как насчет наблюдателя/наблюдаемого шаблона проектирования, который отлично выглядит в моем случае (EventHandler).

В моем случае машина подписывается на мессенджер. (Добавьте машину в список вызовов). Когда произошла ловушка, я отправляю сообщение всем машинам, на которые подписаны. (Вызов HandleEvent чтобы справиться с этим)

Преимущества:

  • больше не заботится о GetInvocationList(), просто используйте (+=) и (-=) чтобы решить, кому отправить ловушку.

  • Проще понять логику моей программы.

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

И спасибо за ваши комментарии и предложения, это было бы очень полезно!

Я прочитал статью MSDN EventArgs, которую предложил Мэтью Уотсон.

Вот моя версия события:

public class TrapInfoEventArgs : EventArgs
{
    public int info { get; set; }
    public string  ip { get; set; }
    public string cause { get; set; }
}
public class trap
{
    public event EventHandler<TrapInfoEventArgs> TrapOccurred;

    protected virtual void OnTrapOccurred(TrapInfoEventArgs e)
    {
        EventHandler<TrapInfoEventArgs> handler = TrapOccurred;
        if (handler != null)
        {
            handler(this, e);
        }
    }


    public void run()
    {
        //While(true) 
        // If a trap occurred, notify the subscriber
        for (; ; )
        {
            Thread.Sleep(500);
            TrapInfoEventArgs args = new TrapInfoEventArgs();
            args.cause = "Shut Down";
            OnTrapOccurred(args);
        }
    }
}
public class machine
{
    public void c_TrapOccurred(object sender, TrapInfoEventArgs e)
    {
        Console.WriteLine("<Alert>: cauese/{0}, info/ {1}, ip/{2}, time/{3}",
            e.cause, e.info, e.ip, DateTime.Now.ToString());
    }
}
class Program
{
    static void Main(string[] args)
    {
        trap t = new trap();
        machine machineA = new machine();
        t.TrapOccurred += machineA.c_TrapOccurred; //notify machine A
        t.run();
    }
}
4b9b3361

Ответ 1

Разница между событием и делегатом заключается в том, что:

Объявление события добавляет уровень защиты на экземпляр делегата. Эта защита препятствует тому, чтобы клиенты делегата сбрасывали делегата и его список вызовов, и позволяет только добавлять или удалять цели из списка вызовов.

Смотрите Каковы различия между делегатами и событиями?

2) На мой взгляд, ваш подписчик не должен свободно менять делегатов. Один подписчик может назначить = вместо того, чтобы добавить +=. Это назначит нового делегата, поэтому предыдущий делегат с его списком вызовов будет потерян, а предыдущие подписчики больше не будут вызываться. Так что вам стоит обязательно использовать Event. Или вы можете изменить свой код, чтобы сделать свой делегат закрытым, и написать дополнительные функции для управления им, чтобы определить собственное поведение события.

 //preventing direct assignment
 private myDelegate del ;

    public void AddCallback(myDelegate m){
        del += m;
    }

    public void RemoveCallback(myDelegate m){
        del -= m;
    }

    //or
    public static trap operator +(trap x,myDelegate m){
        x.AddCallback(m);
        return x;
    }
    public static trap operator -(trap x, myDelegate m)
    {
        x.RemoveCallback(m);
        return x;
    }

//usage  

//t.AddCallback(new trap.myDelegate(notify));
  t+=new trap.myDelegate(notify);

Ответ 2

Гораздо лучше использовать event для вашего примера.

  • А event понимается дизайнерами Visual Studio Form и WPF, поэтому вы можете использовать IDE для подписки на события.

  • При создании events вам не нужно писать свою собственную обработку foreach для итерации через них.

  • events - это то, как большинство программистов ожидают, что эта функциональность будет доступна.

  • Если вы используете делегат, потребительский код может обходиться с ним способами, которые вы хотите предотвратить (например, сбросом своего списка вызовов). events не позволяют этого делать.

Что касается второго вопроса: используя event, вы должны создать класс, полученный из EventArgs, для хранения данных и передать это событие, когда вы его поднимете. Затем потребитель получит доступ к нему.

Подробнее см. здесь: http://msdn.microsoft.com/en-us/library/system.eventargs.aspx