System::EventHandler<T>
Combined delegate type and event subscriber list. Wraps std::function subscribers.
include/System/EventHandler.hpp
Status: Implemented
Overview
C# has separate concepts for the delegate type and the event keyword, which enforces
encapsulation. sharp-runtime folds both into a single EventHandler<T> class that
acts as both the delegate type and the subscriber list.
The template parameter T must derive from System::EventArgs.
Class Definition (abbreviated)
namespace System {
template<typename T>
class EventHandler {
public:
using HandlerType = std::function<void(Object*, T)>;
void Add(HandlerType handler);
void Remove(HandlerType handler);
void Raise(Object* sender, T args);
void Invoke(Object* sender, T args); // alias for Raise
EventHandler<T>& operator+=(HandlerType handler);
EventHandler<T>& operator-=(HandlerType handler); // needs verification
int Size() const;
bool Empty() const;
private:
std::vector<HandlerType> handlers_;
};
}
Methods
Add()
void Add(HandlerType handler);
Appends a subscriber function to the internal list. Same as operator+=.
Remove()
void Remove(HandlerType handler);
Removes a previously added subscriber. Note: removing std::function objects
requires matching by address or wrapping — see the note below.
Raise() / Invoke()
void Raise(Object* sender, T args);
void Invoke(Object* sender, T args);
Calls all registered subscribers in order with the given sender and args.
operator+=
EventHandler<T>& operator+=(HandlerType handler);
Adds a subscriber. Mirrors C# myEvent += handler; syntax.
Size() / Empty()
int Size() const;
bool Empty() const;
Returns the number of registered subscribers / whether the list is empty.
Usage Example
// EventArgs subclass
class ButtonClickArgs : public System::EventArgs {
public:
int x, y;
ButtonClickArgs(int x, int y) : x(x), y(y) {}
};
// Class with an event
class Button : public System::Object {
public:
System::EventHandler<ButtonClickArgs> Click;
GetTypeNameHPP();
void press(int x, int y) {
if (!Click.Empty()) {
Click.Raise(this, ButtonClickArgs(x, y));
}
}
};
// Subscribing
Button btn;
btn.Click += [](System::Object* sender, ButtonClickArgs args) {
std::cout << "Clicked at " << args.x << "," << args.y << "\n";
};
// Firing
btn.press(10, 20);
Comparison with C#
| C# concept | sharp-runtime equivalent |
|---|---|
delegate void Eh(object s, EventArgs e) | EventHandler<T>::HandlerType (std::function) |
event EventHandler<T> Click | EventHandler<T> Click (public field) |
Click += handler | Click += handler (same) |
Click -= handler | Click.Remove(handler) or Click -= handler |
Click?.Invoke(this, args) | if (!Click.Empty()) Click.Raise(this, args) |
event keyword. sharp-runtime does not enforce that only the
declaring class can Raise the event — all access is public on the
EventHandler<T> object. For encapsulation, expose only the operator+=
in the public interface if needed.
std::function objects are not equality-comparable, which makes Remove
tricky. A common pattern is to store the handler in a variable and remove by the same address,
or use a wrapper with an ID. The exact mechanism in sharp-runtime's Remove
implementation is: Needs verification
Related
- Delegates — full discussion of Action, Func, Predicate, EventArgs, EventHandler
System::EventArgs— base class for all event argument types (System/EventArgs.hpp)