I decompiled an assembly using ILSpy, and one class in particular got my attention:
public class CustomTextStream : NetworkStream
{
private EventHandler<CustomEventArgs> someEvent;
public event EventHandler<CustomEventArgs> SomePublicEvent
{
add
{
EventHandler<CustomEventArgs> eventHandler = this.someEvent;
EventHandler<CustomEventArgs> eventHandler2;
do
{
eventHandler2 = eventHandler;
EventHandler<CustomEventArgs> value2 =
(EventHandler<CustomEventArgs>)Delegate.Combine(eventHandler2, value);
eventHandler =
Interlocked.CompareExchange<EventHandler<CustomEventArgs>>(
ref this.someEvent, value2, eventHandler2);
}
while (eventHandler != eventHandler2);
}
remove
{
// similar stuff...
}
}
}
Further in the code, seems like private delegate is used to fire an actual event:
if (something != null && somethingElse != 0)
{
this.someEvent(this, new CustomEventArgs(someArg));
}
The question: Can someone guess what could be the idea behind this custom accessors, assuming that some "compile/decompile magic" didn't take place? I'm not much familiar with IL, btw...
(Side note: the application is multi-threaded and utilizes networking, obviously.)
This is a new event handler code generated by compiler. It was introduced in C# 4 (C# 3 version was different)
Interlocked.CompareExchange compares first argument with third, and if they are equal, replaces first argument with second. This is a thread-safe operation. Loop is used for a case when after assigning a variable eventHandler2 and before check, another thread changes this delegate. In this case, Interlocked.CompareExchange does not perform exchange, loop condition does not evaluate to true and next attempt is made.
C# 3 generated simple code in event handlers:
add { lock(this) { changed = changed + value; } }
Which had lower performance and could introduce deadlocks.
There is a great series of articles on this subject:
Events get a little overhaul in C# 4
Events get a little overhaul in C# 4, Part II
Related
In the latest video by Rx team Bart De Smet: Rx Update - .NET 4.5, Async, WinRT I saw that WinRT events exposed to .NET by some really strange metadata, more preciesly - add_/remove_ pair methods signature:
EventRegistrationToken add_MyEvent(EventHandler<MyEventArgs> handler) { … }
void remove_MyEvent(EventRegistrationToken registrationToken) { … }
It looks really great, allowing unsubscribing from event by "disposing" the registration token (Rx does the same kind of thing, returning IDisposable instance from Subscribe() method). So it's became possible to easily unsubscribe lamba-expressions from events, but...
So how does C# allows for working with this kind of events? In .NET it's possible to subscribe an method (static and instance) with one instance on delegate and unsubscribe with completely another delegate instance pointed to the same method. So if I using an WinRT event and just do unsubscribing of some delegate type instance in C#... where did compiler get the correct EventRegistrationToken? How all this magic works?
-- update --
Actually EventRegistrationToken doesn't allows to unsubscribe simply by calling some kind of Dispose() method, that is really sadly:
public struct EventRegistrationToken
{
internal ulong Value { get; }
internal EventRegistrationToken(ulong value)
public static bool operator ==(EventRegistrationToken left, EventRegistrationToken right)
public static bool operator !=(EventRegistrationToken left, EventRegistrationToken right)
public override bool Equals(object obj)
public override int GetHashCode()
}
-- update2 --
WinRT interoperability actually uses global table of registration tokens when subscribing WinRT events with managed objets. For example, interop code for removing handlers looks like this:
internal static void RemoveEventHandler<T>(Action<EventRegistrationToken> removeMethod, T handler)
{
object target = removeMethod.Target;
var eventRegistrationTokenTable = WindowsRuntimeMarshal.ManagedEventRegistrationImpl.GetEventRegistrationTokenTable(target, removeMethod);
EventRegistrationToken obj2;
lock (eventRegistrationTokenTable)
{
List<EventRegistrationToken> list;
if (!eventRegistrationTokenTable.TryGetValue(handler, out list)) return;
if (list == null || list.Count == 0) return;
int index = list.Count - 1;
obj2 = list[index];
list.RemoveAt(index);
}
removeMethod(obj2);
}
That is really sadly.
When you add or remove a delegate to an WinRT event, like this:
this.Loaded += MainPage_Loaded;
this.Loaded -= MainPage_Loaded;
It looks just like you were working with normal .Net events. But this code actually compiles to something like this (Reflector seems to have some trouble decompiling WinRT code, but I think this is what the code actually does):
WindowsRuntimeMarshal.AddEventHandler<RoutedEventHandler>(
new Func<RoutedEventHandler, EventRegistrationToken>(this.add_Loaded),
new Action<EventRegistrationToken>(remove_Loaded),
new RoutedEventHandler(this.MainPage_Loaded));
WindowsRuntimeMarshal.RemoveEventHandler<RoutedEventHandler>(
new Action<EventRegistrationToken>(this.remove_Loaded),
new RoutedEventHandler(this.MainPage_Loaded));
This code won't actually compile, because you can't access the add_ and remove_ methods from C#. But you can that in IL, and that's exactly what the compiler does.
It looks like WindosRuntimeMarshal keeps all those EventRegistrationTokens and uses them to unsubscribe when necessary.
Would you accept "there are some amazingly clever people working on the C# language projection" as an answer?
More seriously, what you've discovered is the low level ABI (binary) implementation of the event pattern, the C# language projection knows this pattern and knows how to expose it as C# events. There are classes inside the CLR that implement this mapping.
Hypothetically speaking, if I had two methods (event handlers) driven by the same event, which method is executed first?
Example:
obj.SomeEvent += new SomeEventHandler(method1);
obj.SomeEvent += new SomeEventHandler(method2);
Which is called first?
Thanks!
It's up to the event publisher, but usually it would be whichever handler was added to the event first. That's the default implementation for an event which is basically implemented using a delegate. So for example:
SomeDelegate eventHandlers = null;
eventHandlers += FirstHandler;
eventHandlers += SecondHandler;
eventHandlers(...);
That will definitely call FirstHandler before SecondHandler. However, there's no guarantee that an event will be implemented just using delegates like that.
EDIT: While the event handling behaviour is up to the event publisher, the delegate combination part is well-specified in the C# language specification, section 7.8.4:
[...] Otherwise, the result of the operation is a new delegate instance that, when invoked, invokes the first operand and then invokes the second operand.
The BCL Delegate.Combine method makes a similar guarantee (emphasis mine):
(Return value) A new delegate with an invocation list that concatenates the invocation lists of a and b in that order. Returns a if b is null, returns b if a is a null reference, and returns a null reference if both a and b are null references.
The first subscribed one. "First in - first served".
The default implementation will cause event handlers to be called in the order they were added, however, it is possible to customize this behaviour. If the behaviour is customized, the client cannot tell this. So the real answer to your question is that the order in which event handlers is raised "depends" and could even change at runtime, however, the vast majority of events have default implementation.
For example:
public class ReverseBling
{
private readonly List<EventHandler> _blings = new List<EventHandler>();
public event EventHandler Bling
{
add
{
_blings.Add(value);
}
remove
{
_blings.Remove(value);
}
}
public void RaiseBling()
{
for (int i = _blings.Count - 1; i >= 0; i--)
{
_blings[i](this, EventArgs.Empty);
}
}
}
private static void Main()
{
ReverseBling bling = new ReverseBling();
bling.Bling += delegate { Console.WriteLine(0);};
bling.Bling += delegate { Console.WriteLine(1); };
bling.Bling += delegate { Console.WriteLine(2); };
bling.RaiseBling();
}
Output:
2
1
0
There is no way of telling which event handler will be invoked first. Many people think the first one to subscribe will be invoked first (which is normally the case) but not specified by the CLI.
Is there any best practice with respect to coding style with respect to explicit use of the delegate keyword instead of using a lambda?
e.g.
new Thread(() =>
{
// work item 1
// work item 2
}).Start();
new Thread(delegate()
{
// work item 1
// work item 2
}).Start();
I think the lambda looks better. If the lambda is better style, what's the point of having a delegate keyword, other than for the fact that it existed before lambdas were implemented?
Lambda syntax is much more generalised, and the designers have said that they'd ideally remove the old overlapping syntaxes (dont have a citation, but it's probably Eric Lippert or Jon Skeet in a book or a podcast).
But delegate allows you to ignore parameters, e.g.:
object.Event += delegate { };
versus having to say:
object.Event += (sender,args) => { };
which can be very useful in large argument lists and/or to make the code more resilient to refactoring.
EDIT: As pointed out by Yann Schwartz in another answer (now unfortunately deleted), a very neat usage of this trick is in order to provide a default hander for an event using the Null Object pattern:-
class MyClassThatFiresWithoutTheTrick
{
public event EventHandler MyEvent; // implicit = null
// Need a method to keep this DRY as each fire requires a null check - see Framework Design Guidelines by Abrams and Cwalina
protected virtual void OnMyEvent()
{
// need to take a copy to avoid race conditions with _removes
// See CLR via C# 3rd edition p 264-5 for reason why this happens to work
//var handler = MyEvent;
// BUT THIS is the preferred version
var handler = Interlocked.CompareExchange( ref MyEvent, null, null);
// Need to do this check as it might not have been overridden
if( handler == null)
return;
handler( this, EventArgs.Empty );
}
}
class MyClassThatFiresWithTheTrick
{
public event EventHandler MyEvent = delegate{};
protected virtual void OnMyEvent()
{
MyEvent( this, EventArgs.Empty );
}
}
(though what you might often end up doing is an Inline Method of OnMyEvent, making the code even shorter again.)
I'm sure I've seen this around before but I'm wondering how I should raise an event thread-safely.
I have a message despatch thread which looks somthing like.
while(_messages > 0){
Message msg;
// get next message
if (MessageDispatched != null)
MessageDispatched(this, new MessageDispatchedEventArgs(msg.Msg, msg.Params));
}
I can see that it may be posible for MessageDispatched to be come null after the check. from a MS blog I've seen:
var handler = MessageDispatched;
if (handler != null)
handler(this, new MessageDispatchedEventArgs(msg.Msg, msg.Params));
Which does stop the possibility of the reference becoming null after the check occurring. I'm wondering how to handle the case where the delegate is disposed (or even if it can?)
Should I just need to stick a try / catch around it, as its probably very rarely going to occur?
Edit
After reading answers I've considered making my class to handle this - quickly it looks something whats below, but I'm running into a few issues which make it not as clean as I want - maybe someone has an idea how to do that?
public class ThreadSafeEvent<TDelegate>
// where TDelegate : Delegate why is this a non allowed special case???
{
List<TDelegate> _delegates = new List<TDelegate>();
public void Subscribe(TDelegate #delegate)
{
lock (_delegates)
{
if (!_delegates.Contains(#delegate))
_delegates.Add(#delegate);
}
}
public void Unsubscibe(TDelegate #delegate)
{
lock (_delegates)
{
_delegates.Remove(#delegate);
}
}
// How to get signature from delegate?
public void Raise(params object[] _params)
{
lock (_delegates)
{
foreach (TDelegate wrappedDel in _delegates)
{
var del = wrappedDel as Delegate;
del.Method.Invoke (del.Target, _params);
}
}
}
}
The latter structure will make sure you won't get a null reference exception calling the handler on non-Itanium architectures.
However, it leads to another possible issue -- it's possible for a client that registered an event handler to have the handler called after it's been removed. The only way to prevent that is to serialize raising the event and registering the handler. However, if you do that, you have a potential deadlock situation.
In short, there are three potential classes of ways this can break -- I go with the way you've done it here (and MS recommends) and accept that it is possible for an event handler to get called after it is unregistered.
Please, check this out: Checking for null before event dispatching… thread safe?
Read this post from Eric Lippert : Events and Races
Is it possible to somehow shorten this statement?
if (obj != null)
obj.SomeMethod();
because I happen to write this a lot and it gets pretty annoying. The only thing I can think of is to implement Null Object pattern, but that's not what I can do every time and it's certainly not a solution to shorten syntax.
And similar problem with events, where
public event Func<string> MyEvent;
and then invoke
if (MyEvent != null)
MyEvent.Invoke();
From C# 6 onwards, you can just use:
MyEvent?.Invoke();
or:
obj?.SomeMethod();
The ?. is the null-propagating operator, and will cause the .Invoke() to be short-circuited when the operand is null. The operand is only accessed once, so there is no risk of the "value changes between check and invoke" problem.
===
Prior to C# 6, no: there is no null-safe magic, with one exception; extension methods - for example:
public static void SafeInvoke(this Action action) {
if(action != null) action();
}
now this is valid:
Action act = null;
act.SafeInvoke(); // does nothing
act = delegate {Console.WriteLine("hi");}
act.SafeInvoke(); // writes "hi"
In the case of events, this has the advantage of also removing the race-condition, i.e. you don't need a temporary variable. So normally you'd need:
var handler = SomeEvent;
if(handler != null) handler(this, EventArgs.Empty);
but with:
public static void SafeInvoke(this EventHandler handler, object sender) {
if(handler != null) handler(sender, EventArgs.Empty);
}
we can use simply:
SomeEvent.SafeInvoke(this); // no race condition, no null risk
What you're looking for is the Null-Conditional (not "coalescing") operator: ?.. It's available as of C# 6.
Your example would be obj?.SomeMethod();. If obj is null, nothing happens. When the method has arguments, e.g. obj?.SomeMethod(new Foo(), GetBar()); the arguments are not evaluated if obj is null, which matters if evaluating the arguments would have side effects.
And chaining is possible: myObject?.Items?[0]?.DoSomething()
A quick extension method:
public static void IfNotNull<T>(this T obj, Action<T> action, Action actionIfNull = null) where T : class {
if(obj != null) {
action(obj);
} else if ( actionIfNull != null ) {
actionIfNull();
}
}
example:
string str = null;
str.IfNotNull(s => Console.Write(s.Length));
str.IfNotNull(s => Console.Write(s.Length), () => Console.Write("null"));
or alternatively:
public static TR IfNotNull<T, TR>(this T obj, Func<T, TR> func, Func<TR> ifNull = null) where T : class {
return obj != null ? func(obj) : (ifNull != null ? ifNull() : default(TR));
}
example:
string str = null;
Console.Write(str.IfNotNull(s => s.Length.ToString());
Console.Write(str.IfNotNull(s => s.Length.ToString(), () => "null"));
Events can be initialized with an empty default delegate which is never removed:
public event EventHandler MyEvent = delegate { };
No null-checking necessary.
[Update, thanks to Bevan for pointing this out]
Be aware of the possible performance impact, though. A quick micro benchmark I did indicates that handling an event with no subscribers is 2-3 times slower when using the the "default delegate" pattern. (On my dual core 2.5GHz laptop that means 279ms : 785ms for raising 50 million not-subscribed events.). For application hot spots, that might be an issue to consider.
Yes, in C# 6.0 -- https://msdn.microsoft.com/en-us/magazine/dn802602.aspx.
object?.SomeMethod()
This article by Ian Griffiths gives two different solutions to the problem that he concludes are neat tricks that you should not use.
Cerating extention method like one suggested does not really solve issues with race conditions, but rather hide them.
public static void SafeInvoke(this EventHandler handler, object sender)
{
if (handler != null) handler(sender, EventArgs.Empty);
}
As stated this code is the elegant equivalent to solution with temporary variable, but...
The problem with both that it's possible that subsciber of the event could be called AFTER it has unsubscribed from the event. This is possible because unsubscription can happen after delegate instance is copied to the temp variable (or passed as parameter in the method above), but before delegate is invoked.
In general the behaviour of the client code is unpredictable in such case: component state could not allow to handle event notification already. It's possible to write client code in the way to handle it, but it would put unnecesssary responsibility to the client.
The only known way to ensure thread safity is to use lock statement for the sender of the event. This ensures that all subscriptions\unsubscriptions\invocation are serialized.
To be more accurate lock should be applied to the same sync object used in add\remove event accessor methods which is be default 'this'.
I agree with the answer by Kenny Eliasson. Go with Extension methods. Here is a brief overview of extension methods and your required IfNotNull method.
Extension Methods ( IfNotNull method )
Maybe not better but in my opinion more readable is to create an extension method
public static bool IsNull(this object obj) {
return obj == null;
}
I have made this generic extension that I use.
public static class ObjectExtensions {
public static void With<T>(this T value, Action<T> todo) {
if (value != null) todo(value);
}
}
Then I use it like below.
string myString = null;
myString.With((value) => Console.WriteLine(value)); // writes nothing
myString = "my value";
myString.With((value) => Console.WriteLine(value)); // Writes `my value`
There is a little-known null operator in C# for this, ??. May be helpful:
http://weblogs.asp.net/scottgu/archive/2007/09/20/the-new-c-null-coalescing-operator-and-using-it-with-linq.aspx