Object Reset method or new reference for event subscribers? - c#

(Using VS2010. Assume performance is not an issue).
I have a particular object that implements events for all its property changes. Sometimes it will be necessary to "reset" the object to all its default property values. The easiest way to do this is simply construct a new object:
Object1= New MyObject
However, for any event subscribers to the original object, this is equivalent to a change of all property values. For example, if a subscriber was listening only for updates to property A, now it must also be aware of the possibility of new object construction. This seems to add extra effort for subscribers. (For example, maybe I would have to create a "NewObjectAssigned" event, and subscribers to property changes would need to handle that as well.)
So instead I was thinking of outfitting the object with a Reset method, so the above code changes to:
Object1.Reset
That way the Object1 reference never changes, and the Reset would manually change all properties to default values, thereby triggering all propertychanged events. But this also doesn't feel quite right, and cumbersome compared to just declaring a new object. I guess it irks me to need a method that either manually resets all properties or raises all changed events - I'd have to remember to update this method whenever new properties are added to the class. Or perhaps this isn't as problematic as I'm making it out to be.
This is a simple enough scenario that I'm sure there is a best practices for this, one way or another. Which is preferable?

If you need your event handlers to stay attached, then you'll want to use a reset instead of creating a new instance. If your object implements INotifyPropertyChanged, then you can send a single event for the reset with PropertyName set to null.
From MSDN:
An Empty value or null for the propertyName parameter indicates that all of the properties have changed.

I think I agree with Peter Ritchie's first comment, that my original question was lacking in details necessary to determine a "preferable" method. As it stands, I'm probably going with his suggestion of a wrapper class, that will be responsible for handling new object references and exposing events to subscribers.

Related

How does PropertyDescriptor.AddValueChanged work?

I'm intersted in the details of this method.
How and by what are property's value changes being tracked?
Andrew Smith has a cool blog post about it which I think it can be helpful for you.
The solution that I have seen given for this is to get to the
PropertyDescriptor and use its AddValueChanged method to provide an
EventHandler to receive a notification when the property has changed.
Sometimes, the reply will mention/use DependencyPropertyDescriptor
directly but its the same thing since that is just a derived
PropertyDescriptor that provides additional information about the
underlying DependencyProperty it represents. You can get to this
property descriptor in a few ways but the most common are to get it
from the TypeDescriptor.GetProperties method or using the
DependencyPropertyDescriptor.FromProperty.
The issue with this approach is that it will root your object so it
will never get collected by the GC. There have been plenty of
discussions about how hooking events (particularly static events) can
root your object so I won’t go into great detail there. While it does
not seem that you are hooking a static event in this case, in essence
you are. When you add a handler to a property descriptor, that
property descriptor stores the delegate in a hashtable keyed by the
object whose property you are hooking. A delegate/handler is basically
a pointer to a method on an object (or no object if its for a static
method) so that means the property descriptor has a reference to your
object as well as the object whose value you are watching (since that
is the key into the hashtable). The property descriptors themselves
are cached statically so the hashtable is kept around and therefore
your object and the one you are watching are as well.
PropertyDescriptor is an abstract class, so there are presumably many answers to how the value changed event is fired depending on the specific implementation you have at hand. But probably a common case is when a PropertyDescriptor has been acquired through reflection, in which case I think an object of ReflectPropertyDescriptor is returned.
Looking in the reference source for that class, you can see that the event is raised ONLY when the SetValue() method is called. To my understanding this means that if you simply did this:
someObject.A = "value";
there would be no ValueChanged event raised.
However if you got the ReflectPropertyDescriptor for property A and used it to indirectly set the value, like this:
descriptor.SetValue(someObject, "value");
that would raise the event.
To think about this from another point of view, it seems the CLR has no way to actually raise an event at a more fundamental level when a property value is set. I assume something like that would have overhead that would ordinarily be undesirable because each set (really just a function call) would have to check for event subscribers even if there were none, each time a value is set on any property.

How to have objects/Controls GC'd despite being subscribed to an event

I have objects subscribing to a custom event so I can change them all them at once. Trouble is, that that will never let them go out of scope and be garbage-collected. Even nulling Controls will not null the Controls contained in them. In fact, even the nulled controls will not be collected! (Please do correct me if I'm wrong on any point.)
So I thought of a solution which would be to wrap the event in a class, create an instance of that class and use it, and then null it when I want to let the objects get GC'd, and create a new instance of it to continue.
However, I have two questions about it:
Will it actually work, or will the objects still evade being GC'd?
Is there any simpler, more straightforward way to achieve this?
EDIT: part 2 has been answered (in a comment to an answer). Simply do: event_name = null;. I'm still wondering, though, about part 1 - would it work?
You need to unsubscribe from your event. This works just like subscribing, but uses the -= operator instead of +=.
Example:
foo.SomeEvent-= new EventHandler(foo_SomeEvent);
The answer to part 2 (by Servy's comments):
event_name = null;

How to decide between a method or event?

I read a question ages ago "How do C# Events work behind the scenes?" and Jon answered that all events are similar to methods...
In a purely hypothetical situation, I was wondering if someone could explain or point me to a resource that says when to use an event over a method?
Basically, If I want to have a big red/green status picture which is linked to a Bool field, and I wanted to change it based on the value of the bool, should I:
a) Have a method called Changepicture which is linked to the field and changes the state of the bool and the picture.
b) Have a get/set part to the field and stick an event in the set part.
c) Have a get/set part to the field and stick a method in the set part.
d) Other?
To gain more information about events see this post.
You have options.
If your object already implements INotifyPropertyChanged and your red/green picture is a control which supports databinding, then you can simply fire the NotifyPropertyCHanged event on the bool's set method, and add a databinding on that property to your control.
If not implementing INotifyPropertyChanged, I would still recommend doing something similar. I.e. creating your own event handler, and having the reg/green picture subscribe to the event. Just straight up calling a method from the set of your property creates a tight coupling, which is generally a bad thing to do.
The answer is: It depends.
If your boolean value is in the codebehind class of your visual component (e.g. WinForm) you can call a method ChangePicture without doing strange things. But if your boolean value is architectural more far away from the visual component an event is the right way to handle the scenario because you can not easily call a method on the visual component because the class that contains the boolean value perhaps doesn´t even know your visual component exists. :)
The best way to figure out what you should do is to look at classes in the .NET framework and see how they are designed.
Methods are "doers" or "actions", while you can see events as notification mechanisms. That is if others could be interested is being notified when something happens in an object then you can surface an event and have one or more subscribers to these events.
Since events in .NET are multi-cast, meaning multiple objects can subscribe and therefore be notified of an event happening, that may be other reason to raise an event in your objects. Events also follow the observer pattern in that the subject (your class) is really unaware of the subscribers (loosely coupled). While in order to call a method, the secondary object needs to have a reference to an instance of your class.
Note that, a method in your class eventually raises and event. So let's say you have a method in your class called ChangePicture. Then in the method's implementation, you could eventually raise an event PictureChanged. if someone is interested in being notified of this event, they can subscribe to this event. This someone is typically not the one that made the method call to change the picture.
Events are delegates. Delegates are objects. Event's are actually MulticastDelegates (a base class in the .NET framework). These objects eventually call a method, which is the method that gets called as part of the event notification. So they are slightly "heavier" then just a method call, but that should almost never determine your design.

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.

NotifyCollectionChangedAction: object instance on removal?

I am currently implementing the INotifyCollectionChanged interface for a collection with generally quite critical and short-lived items. All of those items implement IDispose, which can be called immediatly before the removal from the collection. I do not have any control about the destruction order, I will just have to take it as it comes.
My trouble is now, how to propagate the "Remove" actions. The NotifyCollectionChangedAction constructor does provide a variant with only the action specified, but I do have an index of the removed item. Sadly there is no overload taking only an index.
So I guess I could:
Only pass the "Remove" action
Pass the remove action along with a "null" object and an index
Pass the remove action along with a disposed object and an index
Which of those would you prefer? I am a little afraid of implementing such a "core" interface wrong and possibly cause not obviously related bugs ...
I couldn't find any guidelines what happens with the items that are in the "change" lists, are there any available?
Sidenote: The collection will not be immediatly bound to WPF, if thats important.
From what I can see in MSDN, the only appropriate sets of data for remove are the overload taking the instance, and the overload taking instance and index. You could try the latter passing just the index; it might work... but given the existence of the first overload, I'm not hopeful. If you don't give it the object, downstream code may have no way of knowing which item changed. So I think you're going to have to pass the object. This shouldn't generally cause issues, as most code is simply going to use it for reference check; the object is still there (it hasn't been collected) - it has just been disposed, where "just" is used... subjectively (as this could still cause issues).
Another option, of course, is to wrap the object in a facade. Then it doesn't matter if the actual object is disposed, set to null and/or garbage-collected; the facade is still there (but it should be coded to handle the object being unavailable).
As a final option; do you have to use their collection? Could you not just wrap that collection, so that you choose when to tell it about these things? THen you retain complete control over lifetimes...
Basically you are borked.
Destruction of objects before the removal is a violation of how the interface should work. Point. You can not control it - then you can not implemtn NotifyCollectionChangedAction properly.
You have to pass the index and the removed object.

Categories