emddudley's WeakEventManager's sample - c#

I am trying to adapt Michael Dudley's sample code for my own implementation of a weak event manager:
Example implementation of weak events using .NET's WeakEventManager
I was wondering where would I put my user code for my own handler? I see this:
private EventHandler mHandler = (s, e) =>
{
CurrentManager.DeliverEvent(s, e);
return;
};
Would I replace the content of that expression with my own custom code?
Thank you,
Kevin

For most cases that handler should stay as it is. As a comment on that answer states, the handler declaration isn't even necessary. The following code for StartListening should be sufficient:
((PropertyValue)source).Changed += DeliverEvent;
If you need to modify the values of s and/or e before delivering the event you can add that code to the handler you posted. But no matter what, DeliverEvent must be called. It loops through and calls ReceiveWeakEvent for all registered listeners and there's no way to get at the list of listeners unless you are storing them in your own ListenerList. So, basically if you modify the event handler, it must still call DeliverEvent or your weak event listeners will never be notified of the event.
If you posted the code you're trying to find a place for, it might be a little easier to help you figure out what you are trying to accomplish and where it should go instead.

Related

What's the standard to make an event that doesn't pass any information along?

I've got an event that literally just lets the user know something happened. They have to manually take action for that event, as no data is passed from it.
However, I'm not sure what would be more idiomatic:
public event Action MyEvent;
//clearly says no arguments
public event EventHandler MyEvent;
//uses the EventHandler class to no effect, but might be more idiomatic.
public event Action<object> MyEvent;
//just like the first but passes the sender if needed.
Which would be the standard way to do this?
The idiomatic approach would be to just use EventHandler. Pass in an appropriate sender if you have one or null otherwise, and EventArgs.Empty.
I know it's somewhat crazy, but that's the convention. Bear in mind that plain EventArgs has no useful information in it, so any EventHandler-based event is basically saying "I may get a sender, but that's probably all."
However, with delegate variance as of C# 2, there is a benefit to this: you can use the same event handling method for all events which follow the convention... so you can have (say) logging event handlers which use reflection to dump whatever information they are given in the EventArgs, even if they don't know about it at compile-time.
It's not the greatest argument in the world for a convention, admittedly - but it's a reasonably strong one. Of course routed events are slightly different in how they're subscribed, but even so the delegates follow the same pattern.

Why pass dummy object to Event Handler in C#?

the following is a function that invokes the event and thus notifies all clients.
public static void OnEventXYZ(XYZEventArgs e)
{
if(EventXYZ!=null)
EventXYZ(new object(),e);
}
This is from a sample code.
What i want to know is "What is the significance of new object()?
is this a syntax followed or only for this situation?
Normally you pass this as the sender parameter of an event handler.
However, in this case, the event is static so you cannot use this. The person who wrote that sample chose to pass new object() instead. I think most people would pass null instead but that's really a matter of personnal preference.
That parameter is for the sender of the event. Normally, you would use this, but that will not work in the static context.
EventXYZ seems to have been written to expect a sender (typical with event handlers). In the case of the static "On"blahBlah event raiser, the sender isn't really dealt with clearly. As another responder posted, it seems to be an attempt to satisfy the sender property of the event args that are passed along to the handler.
A more correct implementation would likely either omit the sender from the EventArgs or allow the static "OnBlahBlah" method an argument that allows the caller to specify the sender.
The use of "new object()" in this case seems like confusing fluff, IMHO. But, then again, we don't technically know the signature of the constructor being used in this case... perhaps the first argument is meant to be "Some random object that will be used as the thing we can blame later when your hard drive gets formatted".. maybe a new, empty, meaningless object is perfect for this.
Another thing to look for is that you may consider rewriting the code to be this:
public static void OnEventXYZ(XYZEventArgs e)
{
var evt = EventXYZ;
if(evt != null)
evt(new object(),e);
}
.. In a nutshell, that is a typical "sender as first argument" pattern that you see in 99% of event args / event handlers. Better examples will probably make more sense.
You can also use ILSpy or Reflector to look at the thousands of event raisers/handlers in the .NET runtime to get better examples of how the common patterns are coded.
EDIT: BTW, it's unusual to see static OnEvent raisers... it's a little odd. Not technically correct, but it sure messes up the typical "'this' as sender" pattern.
Cheers!

Dictionary of events

Is there anything in c# that you can use to create a collection of events like lists, hashsets, and a dictionary in this case? Thankyou.
Sure you can:
Dictionary<String, Delegate> m_events = new Dictionary<String, Delegate>();
In Jeff Richter's Book CLR via C# you can find a complete implementation of an EventSet class.
(Even if you don't have the book you can download the sample code from https://www.wintellect.com/wp-content/uploads/2017/09/CLR-via-C-4th-Edition-Code.zip. The class in question is in "Ch11-1-EventSet.cs".)
As far as the question goes what an event is:
Say you have this line of code in your class:
public event EventHandler<NewMailEventArgs> NewMail;
then the C# compiler will translate the line above into three constructs:
A private delegate field. (Something like: private EventHandler<NewMailEventArgs> NewMail;
A public add_Xxx method (where Xxx is the Event name) that interested subscribers can use to register a callback delegate with the event.
A public remove_Xxx method (where Xxx is the Event name) that subscribers can use to unregister from the event.
(All the gory details can be found in section 11.2 of aforementioned book.)
So in other words the 'thing' you can store in your Event collection class is just a plain old delegate nothing else.
An event is like a property or method; you cant store instances of them. You can use reflection, but this likely isn't what you want.
Did you mean you want to store a list of methods to call when your event is fired? Events already do that.
EDIT:
Ah, I think I get it now. If you just simply fire your event, only the B instances that want it will get it. If you pass into the event args the instance of A that fired the event, then the B instance will be able to tell where it came from. But a B will never get an event from an A that it didn't ask for an event.
EDIT:
Maybe not. You only want to fire an event on one of the B's? Make B implement an interface that has a callback method. Instead of firing an event, call the method on the correct instance of B.
You could use IList with out any trouble. Type T could be any type defined in .net or user defined class.

Why can I check some event handlers for null, some not?

I have a ugly piece of code that adds event handlers. The problem is, if the code is called multiple times, the event handlers are called multiple times.
To solve the problem, I remove the event handler first and then add it.
Now I've seen the following behaviour:
Some event handlers can be checked like:
if (object.event == null) {
//
// Code
//
}
others of the form
if (object.object.event == null) {
//
// Code
//
}
I get a message like 'object.object.event' may only occur left of -= or +=.
(Since I'm using a german version of visual studio, I don't know the correct translation to english).
I have no idea why the behaviour looks this inconsequent so I would be grateful for some information on this.
To be more specific: It's user control.
if (myControl.Event == null) {
//
// works
//
}
if (myControl.TreeView.NodeMouseClick == null) {
//
// doesn't work
//
}
To solve the problem, I remove the event handler first and then add it.
That doesn't solve the problem. The event keyword provides accessors for a delegate object. Much like a property provides accessors for a field. On a property, you always need one get or set. An event has the add, remove and raise accessors. But the compiler will generate a default implementation for them if you don't do so yourself. Which is fairly common.
The advantage of a property accessor is that the backing field can be private. Nobody can mess with it, except the class that contains the field. All access has to go through the get and set accessors. The event keyword works exactly the same way, nobody can mess with the delegate object, except the code in the class that contains the event.
Which shoots a gaping hole in your attempt to avoid raising the event. You cannot mess with the list of subscribers for an event that's declared in another class, the compiler is telling you this. The normal way this is done is setting a bool flag to indicate that events have to be temporarily ignored. The event handler can check that flag and avoid executing any side-effects.
SLaks is correct, and has linked to some excellent resources. Here's a relevant quote from Chris Burrows' blog article:
Let me take a quick detour here and explain to you how the binding of += works in C#. There are two possibilities:
either there is an actual + operator, such as with ints, and x += y binds to “x = x + y” except that x is only evaluated once. This is the compound assignment operator; or
the thing on the left hand side is an event, and x.E += y binds to “x.add_E(y)”. This is the event accessor operator, and in fact this is the only way to bind to an event accessor.
So what do we have in the snippet above? Well, the extra bit of detail that you need to decide is the following rule about field-like events in C#: outside of the class or struct that defines a field-like event E, binding to the name E resolves to the event itself, on which the only legal operation is calling an accessor; inside the class or struct that defines a field-like event E, binding to the name E resolves to the private delegate field.
In your case, when resolving myControl.Event, you're inside the myControl class, so you don't see an event object; instead you see an actual delegate object, which you can compare with null. When resolving myControl.TreeView.NodeMouseClick, you're outside the TreeView class, so you can't access the actual delegate object; all you get is the event object, which cannot be compared to null.
If I understand correctly, all of this wouldn't help you anyway, since presumably after you check for null, you're going to try to fire the TreeView's event for it, which you can't do.
Depending on what you're trying to do, you could probably subclass TreeView and add an internal method that would call the protected TreeView.OnNodeMouseClick method to fire the event.
You can only access the backing field for an event defined in your class.
For more information, see the spec. (Although this has changed in C# 4, the changes are irrelevant to you)
Best practice in your case would be to create a protected internal OnEventName method in each class.
You can only query your own eventhandlers for attached listeners.
Automatic events, like this one:
public event EventHandler SomethingHappened;
are implemented by the compiler using a multicast delegate.
When you write myControl.Event == null, the compiler actually needs to call Delegate.GetInvocationList on that delegate. The compiler does not let you do that unless the code is inside a method of the class exposing the event, hence the error (it only allows you to add or remove from the invocation list).
If we were talking about an event you define in your own class, then you would have the option of exposing the invocation list (e.g. through a method) and doing what you are trying to do. But for existing classes (e.g. TreeView) it is not possible.

Has an event handler already been added?

Is there a way to tell if an event handler has been added to an object? I'm serializing a list of objects into/out of session state so we can use SQL based session state... When an object in the list has a property changed it needs to be flagged, which the event handler took care of properly before. However now when the objects are deserialized it isn't getting the event handler.
In an fit of mild annoyance, I just added the event handler to the Get property that accesses the object. It's getting called now which is great, except that it's getting called like 5 times so I think the handler just keeps getting added every time the object is accessed.
It's really safe enough to just ignore, but I'd rather make it that much cleaner by checking to see if the handler has already been added so I only do so once.
Is that possible?
EDIT: I don't necessarily have full control of what event handlers are added, so just checking for null isn't good enough.
I recently came to a similar situation where I needed to register a handler for an event only once. I found that you can safely unregister first, and then register again, even if the handler is not registered at all:
myClass.MyEvent -= MyHandler;
myClass.MyEvent += MyHandler;
Note that doing this every time you register your handler will ensure that your handler is registered only once.
Sounds like a pretty good practice to me :)
From outside the defining class, as #Telos mentions, you can only use EventHandler on the left-hand side of a += or a -=. So, if you have the ability to modify the defining class, you could provide a method to perform the check by checking if the event handler is null - if so, then no event handler has been added. If not, then maybe and you can loop through the values in
Delegate.GetInvocationList. If one is equal to the delegate that you want to add as event handler, then you know it's there.
public bool IsEventHandlerRegistered(Delegate prospectiveHandler)
{
if ( this.EventHandler != null )
{
foreach ( Delegate existingHandler in this.EventHandler.GetInvocationList() )
{
if ( existingHandler == prospectiveHandler )
{
return true;
}
}
}
return false;
}
And this could easily be modified to become "add the handler if it's not there". If you don't have access to the innards of the class that's exposing the event, you may need to explore -= and +=, as suggested by #Lou Franco.
However, you may be better off reexamining the way you're commissioning and decommissioning these objects, to see if you can't find a way to track this information yourself.
If this is the only handler, you can check to see if the event is null, if it isn't, the handler has been added.
I think you can safely call -= on the event with your handler even if it's not added (if not, you could catch it) -- to make sure it isn't in there before adding.
This example shows how to use the method GetInvocationList() to retrieve delegates to all the handlers that have been added. If you are looking to see if a specific handler (function) has been added then you can use array.
public class MyClass
{
event Action MyEvent;
}
...
MyClass myClass = new MyClass();
myClass.MyEvent += SomeFunction;
...
Action[] handlers = myClass.MyEvent.GetInvocationList(); //this will be an array of 1 in this example
Console.WriteLine(handlers[0].Method.Name);//prints the name of the method
You can examine various properties on the Method property of the delegate to see if a specific function has been added.
If you are looking to see if there is just one attached, you can just test for null.
The only way that worked for me is creating a Boolean variable that I set to true when I add the event. Then I ask: If the variable is false, I add the event.
bool alreadyAdded = false;
This variable can be global.
if(!alreadyAdded)
{
myClass.MyEvent += MyHandler;
alreadyAdded = true;
}
If I understand your problem correctly you may have bigger issues. You said that other objects may subscribe to these events. When the object is serialized and deserialized the other objects (the ones that you don't have control of) will lose their event handlers.
If you're not worried about that then keeping a reference to your event handler should be good enough. If you are worried about the side-effects of other objects losing their event handlers, then you may want to rethink your caching strategy.
i agree with alf's answer,but little modification to it is,,
to use,
try
{
control_name.Click -= event_Click;
main_browser.Document.Click += Document_Click;
}
catch(Exception exce)
{
main_browser.Document.Click += Document_Click;
}
EventHandler.GetInvocationList().Length > 0

Categories