вторник, 24 июня 2014 г.

Delegate та Event


Коротко про Делегат:

Delegate 
- це тип, який представляє собою посилання (ссилку) на методи з певним списком параметрів і типом, що повертається. При створенні екземпляра делегата цей екземпляр можна зв'язати з будь-яким методом з сумісною сигнатурою і типом, що повертається. Метод можна викликати за допомогою екземпляра делегата. Делегат - це reference тип.


Делегати використовують для передачі методів в якості аргументів інших методів. Обробники подій - це методи, які викликані за допомогою делегатів. 

Оголошення делегата: 
    public delegate int CalculateSum(int x, int y);

Делегати є основою Подій (event).
Делегат можна створити присвоївши йому метод з аналогічною сигнатурою або лямбда-вираз, наприклад:
    public delegate int CalculateSum(int x, int y);

    public class SomeDelegateClass
    {
        static int SomeClassMethod(int x, int y)
        {
            return x + y;
        }

        static void Main()
        {
            // Присвоюємо делегату метод з класу з аналогічною сигнатурою
            CalculateSum myDelegate1 = SomeClassMethod;
            // Викликаємо наш делегат
            int result = myDelegate1(2, 2);
            Console.WriteLine("Delegate 1 result = " + result.ToString());

            // Присвоюємо делегату анонімний метод
            CalculateSum myDelegate2 = delegate(int x, int y)
            {
                return 2 * x + 2 * y; // можемо собі робити якусь іншу дію
            };
            result = myDelegate2(2, 2);
            Console.WriteLine("Delegate 2 result = " + result.ToString());

            // Присвоюємо делегату лямбда-вираз
            CalculateSum myDelegate3 = (x, y) => 3 * x + 3 * y;
            result = myDelegate3(2, 2);
            Console.WriteLine("Delegate 2 result = " + result.ToString());
            Console.ReadKey();
        }
    }

Делегат можна оголошувати як в межах класу, так і поза його межами.
Оскільки створений делегат є об'єктом, то його можна передавати як параметр або присвоювати проперті.
Делегати можуть ссилатись не на один метод, а на декілька одразу.

Коротко про Евент:

Event 
- це сутність, що дозволяє класу або об'єкту повідомляти інші класи або об'єкти про виникнення певних ситуацій. Відповідно ті класи або об'єкти, що отримали повідомлення можуть якось на них реагувати.

Оголошення евента: 
      public event EventHandler SomethingChanged;

В даному оголошення EventHandler – це тип-делегат. Отже робимо висновки, що основою роботи евентів є делегати.

Ми звикли оголошувати евент таким чином:

    public class SomeEventClass
    {
        public event EventHandler SomethingChanged;
    }

Компілятор в свою чергу транслює це оголошення в такий код:

    public class SomeEventClass
    {
        EventHandler somethingChanged;
        public event EventHandler SomethingChanged
        {
            add
            {
                EventHandler eventHandler = this.somethingChanged;
                EventHandler comparand;
                do
                {
                    comparand = eventHandler;
                    eventHandler = Interlocked.CompareExchange<EventHandler>
                                                    (ref this.somethingChanged,
                                                    comparand + value, comparand);
                } while (eventHandler != comparand);
            }
            remove
            {
                EventHandler eventHandler = this.somethingChanged;
                EventHandler comparand;
                do
                {
                    comparand = eventHandler;
                    eventHandler = Interlocked.CompareExchange<EventHandler>
                                                    (ref this.somethingChanged,
                                                    comparand - value, comparand);
                } while (eventHandler != comparand);
            }
        }
    }

При явній реалізації евента програміст сам оголошує делегат для евента і вручну додає та удаляє підписників через блоки add/remove (оба блока повинні бути обов'язково).

Евент можна оголошувати тільки в межах класу.
Стандартними типами подій є
  • EventHandler - у випадку коли не потрібно аргументи події передавати
  • EventHandler<TEventArgs>- у випадку коли аргументи події потрібні, тоді ми створюємо клас, який наслідується від EventArgs.
Щоб підписатись або відписатись до/від евента ми використовуємо += та -=

Приклад створення свого евента:
    // Створюємо кастомний аргумент
    public class MessageEventArgs : EventArgs
    {
        public string Message { get; private set; }
        public MessageEventArgs(string message)
        {
            Message = message;
        }
    }

    // Створюємо клас, що буде містити евент
    public class Oksana
    {
        // Створюємо делегат - тип нашого евента і в параметрах передаємо аргумент
        public delegate void TalkEventHandler(Oksana sender, MessageEventArgs e);
        // Створюємо евент типу делегату, що ми створили
        public event TalkEventHandler OksanaSaid;
        // Будемо у циклі постійно рейзати наш евент
        public void StartTalk()
        {
            while (true)
            {
                if (OksanaSaid != null)
                {
                    MessageEventArgs message = new MessageEventArgs(
                                                "Bla bla bla at " +
                                                DateTime.Now.ToString());
                    OksanaSaid(this, message);
                }
            }
        }
    }

    public class Student
    {
        // Підписуємось на евент
        public void Subscribe(Oksana oksana)
        {
            oksana.OksanaSaid += 
                     new Oksana.TalkEventHandler(LearnedThatOksanaSaid);
        }

        // Обробляємо евент коли він викличеться в класі Oksana
        private void LearnedThatOksanaSaid(Oksana sender, MessageEventArgs e)
        {
            Console.WriteLine("Learned Oksana's lesson: " + e.Message);
        }
    }

    public class SomeEventClass
    {
        static void Main()
        {
            Oksana oksana = new Oksana();
            Student student = new Student();

            student.Subscribe(oksana);
            oksana.StartTalk();
        }
    }


Отже яка ж різниця між Event ти Delegate

  •  Event – це той самий Delegate, який наділений деякими властивостями за допомогою слова event.
  •  І Event і Delegate можна оголосити полем класу, але на відміну від Delegate, Event не може бути локальною змінною методу.
  • Event не можна запустити поза межами класу, в якому він був оголошений.
  • Event завжди оголошується як поле, а не властивість (якщо не враховувати add/remove).


І на останок декілька корисних лінків


Комментариев нет:

Отправить комментарий