Делегаты и события
Делегаты
О делегате можно подумать как о некоем интерфейсе с четко заданной сигнатурой. Тогда экземпляр делегата - это объект, который этот интерфейс реализует. Он хранит ссылку на метод, и, если метод экземплярный, то и ссылку на экземпляр объекта, в котором «находится» целевой метод. Суть делегата - возможность делать вызов метода с заранее определенной сигнатурой Имея экземпляр делегата, можно вызвать любой существующий метод, сигнатура которого будет идентична сигнатуре метода, определенного в "интерфейсе"(делегате). Делегат объявляется при помощи ключевого слова delegate
public delegate string SasDelegate (int x);
public class Sas
{
public delegate void AsaDelegate (char a, char b);
}
Так как оба делегата имеют доступ public
они доступны всем и вся. Если же доступ явно не указан, но делегат объявлен внутри простанства имен - он будет доступен для всех объектов, находящихся в этом же пространстве.
Если же он объявлен внутри класса или структуры - он будет закрытым, аналогично private
.
При объявлении делегата нельхя использовать static
.
/* По сути, мы создаем новый делегат так же, как и любой объект, но в конструктор помещаем метод. */
SasDelegate sas1 = new SasDelegate(InstanceMethod);
/* Все тоже самое, но целевой метод находится в другом классе(в данном случае в классе OtherInstanceClass) */
SasDelegate sas2 = new SasDelegate(OtherInstanceClass.InstanceMethod);
/* Целевой метод так же может быть статическим */
SasDelegate sas = new SasDelegate(StaticMethod);
Конструктор делегата имеет 2 параметра - сслыку на метод(System.IntPtr) и ссылку на экземпляр объекта(System.Object). Если метод указанный в параметре System.IntPtr статический, параметр System.Object примет значение null.
Экземпляры делегатов могут ссылаться на методы и экземпляры объектов, которые будут вне области видимости по отношению к тому месту в коде, где будет произведён вызов экземпляра делегата. Важно то, что и метод, и экземпляр объекта должны быть находиться в области видимости на момент создания экземпляра делегата. А вот во время вызова ранее созданного экземпляра делегата права доступа и область видимости игнорируются.
Экземпляры делегатов вызываются таким же образом как и обычные методы
string data = sas(228);
События
Событие, это не что иное, как ситуация, при возникновении которой, произойдет действие или несколько действий. Говоря языком программного моделирования, Событие — это именованный делегат, при вызове которого, будут запущены все подписавшиеся на момент вызова события методы заданной сигнатуры. Хоть события и основаны на делегатах, это НЕ экземпляры делегатов.
События являются парами методов, связанные между собой так, чтобы языковая среда чётко знала, что она «имеет дело» не с «простыми» методами, а с методами, которые представляют события. Когда событие срабатывает, происходит поочерёдный (один за другим) вызов обработчиков.
Так как события и делегаты связаны, для создания события потребуется делегат.
class Sas
{
public delegate void MethodContainer();
// /~
}
Событие создается при помощи ключевого слова event.
Событие имеет синтаксис public event <НазваниеДелегата> <НазваниеСобытия>;
НазваниеДелегата — это имя делегата, на который «ссылаются» методы.
class Sas
{
public delegate void MethodContainer();
//Событие mEvent c типом делегата MethodContainer.
public event MethodContainer mEvent;
// /~
}
Следует указать событию методы, которые должны запуститься.
<КлассИлиОбъект>.<ИмяСобытия> += <КлассЧейМетодДолженЗапуститься>.<МетодПодходящийПоСигнатуре>.
//Экземпляры классов которые должны запуститься.
Class1 class1 = new Class1();
Class2 class2 = new Class2();
//Они должны будут как-то среагировать на возникновение события.
//Допустим, у них есть метод React().
//Тогда, подписываем их на событие.
Sas.mEvent += class1.React; // Никаких скобочек - метод не вызывается.
Sas.mEvent += class2.React;
Необходимо создать условие, когда событие будет вызвано.
class Sas
{
public delegate void MethodContainer();
public event MethodContainer mEvent;
private void someMethod()
{
//что-то происходит
//проверка условия
if (somethingIsHappen())
{
mEvent();//Запуск события
}
//Снова что-то происходит
}
}
От события можно отписаться путем <КлассИлиОбъект>.<ИмяСобытия> -= <КлассЧейМетодДолженЗапуститься>.<МетодПодходящийПоСигнатуре>.
Если на событие никто не подписан и его делегат пустой, возникнет ошибка.