Event і delegate в чому відмінність stack overflow російською
Давайте почнемо з того, що event і delegate - це дві різні речі, настільки ж різні, як автомобіль і морквина. Різниця між полем -делегатом і event'ом приблизно така ж, як між полем і властивістю: event іноді виглядає як делегатное поле. Давайте розберемося в цьому.
delegate - це клас. що містить в собі «шаблон» методу, тобто, сигнатуру методу. Мінлива делегатного типу - об'єкт типу MulticastDelegate (точніше, похідного від нього), який може містити один або кілька об'єктів, що становлять методи сумісну із системою «шаблоном» сигнатурою (контр- і коваріантність трохи ускладнює картину). Тобто це як би змінна, яка може містити функції. Для таких змінних визначена операція +. яка комбінує складові-функції в одну нову функцію, і симетрична операція -. Ці операції автоматично породжують похідні операції + = і - =.
event ж - це просто пара методів в класі, що позначаються як add і remove. і мають довільну семантику, обрану програмістом. (Аналог - геттер і сетер властивості.) В імплементації за замовчуванням для event'а заводиться приховане поле делегатного типу, а add / remove додають або прибирають з нього методи (під lock'ом). (Щоб трохи заплутати картину, це приховане поле є по тому ж імені, що і event.) Функції add / remove. складові event. викликаються відповідно як + = і - =. Ніяких операцій + / -. зрозуміло, немає.
Давайте ще пробіжить по відмінності event'а в класі від публічного поля делегатного типу.
Розглянемо випадок, коли event реалізований «за замовчуванням», тобто, з неявним делегатним полем. Відмінність полягає в тому, що:
1) Для делегатного поля у вас повний доступ до нього. Ви можете - також і зовні класу! - розібрати MulticastDelegate на частини і зібрати новий, ви можете замінити його на свій або привласнити йому null. ви можете його викликати, можете його скопіювати собі в змінну. У вас є повний доступ, як і до будь-якого публічного полю. (Це, зрозуміло, кричущим чином порушує инкапсуляцию.)
Для event'а, ви можете лише написати instance.Event + = handler і instance.Event - = handler. що відображається на функції add і remove. які в свою чергу знову-таки викликають + = і - = для автоматично реалізованого делегата. Ніякого іншого доступу у вас немає. Усередині класу ви, однак, можете отримати на читання значення цього делегата, використовуючи ім'я event'а. (Це потрібно, наприклад, для того, щоб викликати цей делегат; VB на відміну від C # має спеціальний метод RaiseEvent з потрібними перевірками.)
Для випадку, коли event реалізується не «за замовчуванням», спільного немає практично нічого. Методи add і remove можуть робити все, що завгодно:
Програміст може завести делегат самостійно і «складати» туди підписані обробники, але це в принципі його добра воля. З іншого боку, все ж рекомендується не ламати очікувану клієнтами семантику класу, і використовувати event за призначенням.
* В сучасних версіях C # для потокобезпечна виклику рекомендується патерн MyEvent? .Invoke (.). Втім, з потокобезпечна у подій не все гладко, як пояснено в статті [2].