Существует шаблон, который используется во всех классах библиотеки. Рекомендуется и для ваших собственных классов, особенно для фреймворка / библиотечного кода. Но никто не остановит вас, когда вы отклонитесь или пропустите несколько шагов.
Вот схема, основанная на простейшем делегате события, System.Eventhandler
.
// The delegate type. This one is already defined in the library, in the System namespace
// the `void (object, EventArgs)` signature is also the recommended pattern
public delegate void Eventhandler(object sender, Eventargs args);
// your publishing class
class Foo
{
public event EventHandler Changed; // the Event
protected virtual void OnChanged() // the Trigger method, called to raise the event
{
// make a copy to be more thread-safe
EventHandler handler = Changed;
if (handler != null)
{
// invoke the subscribed event-handler(s)
handler(this, EventArgs.Empty);
}
}
// an example of raising the event
void SomeMethod()
{
if (...) // on some condition
OnChanged(); // raise the event
}
}
И как им пользоваться:
// your subscribing class
class Bar
{
public Bar()
{
Foo f = new Foo();
f.Changed += Foo_Changed; // Subscribe, using the short notation
}
// the handler must conform to the signature
void Foo_Changed(object sender, EventArgs args) // the Handler (reacts)
{
// the things Bar has to do when Foo changes
}
}
И когда у вас есть информация для передачи:
class MyEventArgs : EventArgs // guideline: derive from EventArgs
{
public string Info { get; set; }
}
class Foo
{
public event EventHandler<MyEventArgs> Changed; // the Event
...
protected virtual void OnChanged(string info) // the Trigger
{
EventHandler handler = Changed; // make a copy to be more thread-safe
if (handler != null)
{
var args = new MyEventArgs(){Info = info}; // this part will vary
handler(this, args);
}
}
}
class Bar
{
void Foo_Changed(object sender, MyEventArgs args) // the Handler
{
string s = args.Info;
...
}
}
Обновление
Начиная с C # 6, вызывающий код в методе «Триггер» стал намного проще, нулевой тест можно сократить с помощью условно-нулевого оператора ?.
без копирования, сохраняя при этом безопасность потока:
protected virtual void OnChanged(string info) // the Trigger
{
var args = new MyEventArgs{Info = info}; // this part will vary
Changed?.Invoke(this, args);
}