Events
From eqqon
(→Events in C#) |
m (→Quick Facts) |
||
(2 intermediate revisions not shown) | |||
Line 4: | Line 4: | ||
An event is just an accessor (+=, -=) to a field holding a MulticastDelegate. The difference between a publicly accessible delegate field and an event are that you cannot overwrite the existing registered delegates, only append or remove. You also cannot reset the private event handler field to null from outside. | An event is just an accessor (+=, -=) to a field holding a MulticastDelegate. The difference between a publicly accessible delegate field and an event are that you cannot overwrite the existing registered delegates, only append or remove. You also cannot reset the private event handler field to null from outside. | ||
- | == Declaration and what the Compiler does under the Surface == | + | == Declaration of an Event (and what the Compiler does under the Surface) == |
The typical declaration of an event in C# looks like this: | The typical declaration of an event in C# looks like this: | ||
public event <type> <name>; | public event <type> <name>; | ||
- | <type> is a derived type of ''MulticastDelegate'' which is a subtype of ''Delegate''. Examples are ''Action<T>'', '' | + | <type> is a derived type of ''MulticastDelegate'' which is a subtype of ''Delegate''. Examples are ''System.Action<T>'', ''System.Windows.Forms.EventHandler'', ... etc. There are hundreds of types derived from MulticastDelegate in mscorelib.dll which is -- in my opinion -- really a mess. A small set of simple generic delegates like Action<T>, Action<T1, T2>, ... etc would be enough. Ok let's have a look at what happens under the hood. The compiler creates a private field with the same name and a pair of public accessors to add and remove delegates: |
- | The compiler creates a private field with the same name and a pair of public accessors to add and remove delegates | + | |
private <type> <name>; | private <type> <name>; | ||
Line 15: | Line 14: | ||
} | } | ||
- | public void | + | public void remove_<name>(<type> value) |
{ | { | ||
this.<name> = (<type>) Delegate.Remove(this.<name>, value); | this.<name> = (<type>) Delegate.Remove(this.<name>, value); | ||
} | } | ||
+ | |||
+ | == Fireing the Event == | ||
+ | Consider again our example event | ||
+ | public event <type> <name>; | ||
+ | Fire the event manually: | ||
+ | if (this.<name> != null) this.<name>( <parameters> ); | ||
+ | Fire the event programmatically: | ||
+ | if (this.<name> != null) | ||
+ | foreach (Delegate d in this.<name>.GetInvocationList()) | ||
+ | d.Method.Invoke(d.Target, <parameters>); | ||
== Quick Facts == | == Quick Facts == | ||
Line 26: | Line 35: | ||
* Unregistering an event that has never been registered (using -= on a null event) has no effect. | * Unregistering an event that has never been registered (using -= on a null event) has no effect. | ||
* There is no built-in mechanism for preventing event recursions. (see [[Preventing Recursive Events]]) | * There is no built-in mechanism for preventing event recursions. (see [[Preventing Recursive Events]]) | ||
+ | * Events may delay your threads execution time by an unknown value. (see [[Asynchronous Events]]) |
Latest revision as of 21:37, 21 December 2007
Contents |
Events in C#
An event is just an accessor (+=, -=) to a field holding a MulticastDelegate. The difference between a publicly accessible delegate field and an event are that you cannot overwrite the existing registered delegates, only append or remove. You also cannot reset the private event handler field to null from outside.
Declaration of an Event (and what the Compiler does under the Surface)
The typical declaration of an event in C# looks like this:
public event <type> <name>;
<type> is a derived type of MulticastDelegate which is a subtype of Delegate. Examples are System.Action<T>, System.Windows.Forms.EventHandler, ... etc. There are hundreds of types derived from MulticastDelegate in mscorelib.dll which is -- in my opinion -- really a mess. A small set of simple generic delegates like Action<T>, Action<T1, T2>, ... etc would be enough. Ok let's have a look at what happens under the hood. The compiler creates a private field with the same name and a pair of public accessors to add and remove delegates:
private <type> <name>; public void add_<name>( <type> value){ this.<name> = (<type>) Delegate.Combine(this.<name>, value); } public void remove_<name>(<type> value) { this.<name> = (<type>) Delegate.Remove(this.<name>, value); }
Fireing the Event
Consider again our example event
public event <type> <name>;
Fire the event manually:
if (this.<name> != null) this.<name>( <parameters> );
Fire the event programmatically:
if (this.<name> != null) foreach (Delegate d in this.<name>.GetInvocationList()) d.Method.Invoke(d.Target, <parameters>);
Quick Facts
- Fireing an Event that has not been registered (==null) raises a NullReferenceException. (annoying)
- Registering for the same event twice with the same delegate means that the delegate will be called twice.
- A delegate that has been registered for the same event multiple times must also be unregistered multiple times.
- Unregistering an event that has never been registered (using -= on a null event) has no effect.
- There is no built-in mechanism for preventing event recursions. (see Preventing Recursive Events)
- Events may delay your threads execution time by an unknown value. (see Asynchronous Events)