чтобы понять различия, вы можете посмотреть эти 2 примера
Пример с делегатами (действие в данном случае - это своего рода делегат, не возвращающий значение)
public class Animal
{
public Action Run {get; set;}
public void RaiseEvent()
{
if (Run != null)
{
Run();
}
}
}
чтобы использовать делегат, вы должны сделать что-то вроде этого
Animale animal= new Animal();
animal.Run += () => Console.WriteLine("I'm running");
animal.Run += () => Console.WriteLine("I'm still running") ;
animal.RaiseEvent();
этот код работает хорошо, но у вас могут быть слабые места.
Например, если я напишу это
animal.Run += () => Console.WriteLine("I'm running");
animal.Run += () => Console.WriteLine("I'm still running");
animal.Run = () => Console.WriteLine("I'm sleeping") ;
с последней строкой кода я переопределил предыдущее поведение только с одним отсутствующим +
(я использовал +
вместо +=
)
Еще одно слабое место в том, что каждый класс, использующий ваш Animal
класс, может поднять его, RaiseEvent
просто вызвав его animal.RaiseEvent()
.
Чтобы избежать этих слабых мест, вы можете использовать events
в C #.
Ваш класс Animal изменится таким образом
public class ArgsSpecial :EventArgs
{
public ArgsSpecial (string val)
{
Operation=val;
}
public string Operation {get; set;}
}
public class Animal
{
public event EventHandler<ArgsSpecial> Run = delegate{} //empty delegate. In this way you are sure that value is always != null because no one outside of the class can change it
public void RaiseEvent()
{
Run(this, new ArgsSpecial("Run faster"));
}
}
вызывать события
Animale animal= new Animal();
animal.Run += (sender, e) => Console.WriteLine("I'm running. My value is {0}", e.Operation);
animal.RaiseEvent();
Отличия:
- Вы используете не общедоступное свойство, а общедоступное поле (с событиями, которые компилятор защищает ваши поля от нежелательного доступа)
- События нельзя назначать напрямую. В этом случае вы не можете выполнить предыдущую ошибку, которую я показал, переопределив поведение.
- Никто за пределами вашего класса не может поднять это событие.
- События могут быть включены в объявление интерфейса, тогда как поле не может
ноты
EventHandler объявлен как следующий делегат:
public delegate void EventHandler (object sender, EventArgs e)
он принимает аргументы отправителя (типа Object) и события. Отправитель имеет значение NULL, если он исходит из статических методов.
Вы также можете использовать EventHAndler
вместо этого этот пример, который используетEventHandler<ArgsSpecial>
обратитесь сюда для документации о EventHandler