views:

86

answers:

3

Hi, On the MSDN, I have found following:

public event EventHandler<MyEventArgs> SampleEvent;

public void DemoEvent(string val)
{
// Copy to a temporary variable to be thread-safe.
    EventHandler<MyEventArgs> temp = SampleEvent; 

Is it reference?
If so I do not understand its meaning as when SampleEvent became null, so does the temp

    if (temp != null)
        temp(this, new MyEventArgs(val));
}
+7  A: 

This is a paranoia thing to do with threading. If another thread unsubscribes the last handler just after you've checked it for null, it could become null and you'll cause an exception. Since delegates are immutable, capturing a snapshot of the delegate into a variable stops this from happening.

Of course, it does have the other side effect that you could (instead) end up raising the event against an object that thinks it already unsubscribed...

But to stress - this is only an issue when multiple threads are subscribing / unsubscribing to the object, which is a: rare, and b: not exactly desirable.

Marc Gravell
A nice, yet precise, explanation :o)
Ardman
Note that you can *always* end up raising the event against a handler that thinks it's unsubscribed - because it could unsubscribe after you've started executing the delegate but before you've reached the one that unsubscribes itself.
Jon Skeet
So the key fact here (to target asker's reasonable question that delegates are of a reference type) is that "delegates are immutable", so this assignment "captur[es] a **snapshot** of the delegate". Right?
AakashM
I thougt immutable means that it does not change itself. Do not understand why its the reason for assigning it to variable.
Petr
@Petr - you capture the **current** value of the delegate field. When code subscribes/unsubscribes, it *replaces* this with a *different* reference (which might well be `null`).
Marc Gravell
Marc, thank you. But if this reference chances (even to null), it will point to null...so I still did not get the point of it.
Petr
@Petr - imagine we just have `if(SomeEvent!=null) SomeEvent(...)`; sequence of events: Thread A does the `null` check (`if(SomeEvent!=null)`) and finds it *isn't* `null`. Thread B *unsubscribes* and in doing so changes the field to `null`. Thread A gets some more CPU cycles and invokes (`SomeEvent(...)`) on a `null` instance. Kabooooooom!
Marc Gravell
Marc, yes, I understand it. But I do not get a point of using variable which holds the reference as you said it changes (as reference does) when original handler changes. So it still can be null..or what am I missing?
Petr
@Petr : once you've obtained the delegate value from the *field* into a *variable*, that *variable* **doesn't** change. The other thread changes the *field*, not your local *variable*. It isolates your thread (that is checking for `null` and invoking the delegate) from other threads (potentially changing the field).
Marc Gravell
Marc, I really appreciate your help. However, to me it seems that its value type.With objects, it would change the variable, right?Object a=new Object();object x=a;
Petr
@Petr - No, it is a reference-type, but immutable (think: like string). When you add a reference it **isn't** `theField.Add(newValue)` - but rather it is `theField = Delegate.Combine(theField, newValue)` - i.e. take the old delegate and the new delegate and combine them to create a **new** delegate instance.
Marc Gravell
@Petr - and in your example, if you then **reassign** `a` (for example, `a = "abc";`), `x` doesn't notice the change. `x` still points to the original `object`. Same concept.
Marc Gravell
Oh, I hope I get it. I have played with it..by practice I learn the best. Only wonder why I cannot find anything about eventhandler being immutable on MSDN.I understand it the following way: A=B -both objects points to some location in memory. When B is set to null (e.g.), A still points to the previous location and so then A is not equal B.
Petr
A: 

hi,
look at this link it explains this explains what you are asking
http://www.codeproject.com/Articles/37474/Threadsafe-Events.aspx

IordanTanev
That article is out of date, since C# 4.0 addresses (and changes) all of these points.
Marc Gravell
A: 

(From what I read in Essential C# 4.0)

Basically, from this C# code:

public class CustomEventArgs: EventArgs {…}
public delegate void CustomEventHandler(object sender, CustomEventArgs a);
public event CustomEventHandler RaiseCustomEvent;

the compiler will generate CIL code (loosely) equivalent to the following C# code:

public delegate void CustomEventHandler(object sender, CustomEventArgs a);

private CustomEventHandler customEventHandler; // <-- generated by the compiler

public void add_CustomEventHandler(CustomEventHandler handler) {
  System.Delegate.Combine(customEventHandler, handler);
}

public void remove_CustomEventHandler(CustomEventHandler handler) {
  System.Delegate.Remove(customEventHandler, handler);
}

public event CustomEventHandler customEventHandler {
  add { add_customEventHandler(value) }
  remove { remove_customEventHandler(value) }
}

When you copy the event, you actually copy the private CustomEventHandler customEventHandler. Since delegate is immutable, the copy won't be affected when the original customEventHandler is modified. You can try this code to see what I mean:

string s1 = "old"; 
string s2 = s1; 
s1 = "new"; // s2 is still "old"

Another important characteristic to note about the generated CIL code is that the CIL equivalent of the event keyword remains in the CIL. In other words, an event is something that the CIL code recognizes explicitly; it is not just a C# construct. By keeping an equivalent event keyword in the CIL code, all languages and editors are able to provide special functionality because they can recognize the event as a special class member.

I guess you were confused mainly because you thought event is a sugar-syntax for a class, right?

Hai Minh Nguyen