As seen in this question: http://stackoverflow.com/questions/231525/raising-c-events-with-an-extension-method-is-it-bad
I'm thinking of using this extension method to safely raise an event:
public static void SafeRaise(this EventHandler handler, object sender, EventArgs e)
{
if (handler != null)
handler(sender, e);
}
But Mike Rosenblum raise this concern in Jon Skeet's answer:
You guys need to add the [MethodImpl(MethodImplOptions.NoInlining)] attribute to these extension methods or else your attempt to copy the delegate to a temporary variable could be optimized away by the JITter, allowing for a null reference exception.
I did some test in Release mode to see if I could get a race condition when the extension method is not marked with NoInlining:
int n;
EventHandler myListener = (sender, e) => { n = 1; };
EventHandler myEvent = null;
Thread t1 = new Thread(() =>
{
while (true)
{
//This could cause a NullReferenceException
//In fact it will only cause an exception in:
// debug x86, debug x64 and release x86
//why doesn't it throw in release x64?
//if (myEvent != null)
// myEvent(null, EventArgs.Empty);
myEvent.SafeRaise(null, EventArgs.Empty);
}
});
Thread t2 = new Thread(() =>
{
while (true)
{
myEvent += myListener;
myEvent -= myListener;
}
});
t1.Start();
t2.Start();
I ran the test for a while in Release mode and never had a NullReferenceException.
So, was Mike Rosenblum wrong in his comment and method inlining cannot cause race condition?
In fact, I guess the real question is, will SaifeRaise be inlined as:
while (true)
{
EventHandler handler = myEvent;
if (handler != null)
handler(null, EventArgs.Empty);
}
or
while (true)
{
if (myEvent != null)
myEvent(null, EventArgs.Empty);
}