I'm working on a Silverlight app using the MVVM pattern. My ViewModel currently consists of a property that represents a collection of Model Objects:
public ObservableCollection<IndexEntry> IndexList
{
get;
set;
}
it also has several methods that will populate that collection with data that comes back from a webservice.
Since instances of this class may be created and destroyed over the course of the application runtime, should I implement IDisposable and set the property's reference to null or will the destruction of this class be sufficient to remove all references to the collection tis property refers to? Are there any caveats that might leave a reference hanging out there?
Thanks.
The only way a reference survives garbage collection is if it is rooted. If there is some other class that is still in use that contains a reference to the ObservableCollection, then the ObservableCollection will not be destroyed, regardless of whether or not you set it to null. For example, suppose there is one 'in memory' object that is your collection. You have one reference to it, in your property. Some other code executes the line "ObservableCollection<> myOtherReference = YourObject.IndexList;". They now have a reference to the actual memory object, too. Making your property reference null will only eliminate your property's reference; the 'myOtherReference' reference is unaffected, as it is now pointing at the memory directly, and not at your property. If you really want to eliminate this item from memory, you need to remove ALL the references, or implement some decisive 'dispose' logic, at which point "myOtherReference" would be a pointer to a disposed object, and any call to it will throw an exception.
GWLlosa is spot on. In addition, Silverlight data binding will keep your ViewModel pinned as long as you have a Binding reference to it. In other words, you’ll either need to remove your ViewModel from the DataContext of the view (by setting View.DataContext=null) or your view will need to be removed from the visual tree before your ViewModel is released. Implementing IDisposable won’t help and I wouldn’t really recommend it for this. IDisposable is intended for cleaning up unmanaged resources or for having more control over your managed resource disposal. It’s not necessary in this case if you properly understand how bindings and references work and just let the garbage collector take care of things. This article could help:
Finding Memory Leaks in WPF Applications
It’s primarily WPF but you can use the techniques on Silverlight too.
Cool to see you using ViewModel by the way. I’m a big fan of the pattern.
Related
I'm implementing a piece of sensitive software and I can see a possible "failure point"/"security leak" IF in the future someone sticks a public set on a specific property.
Besides the obvious //Do not make this property set operator public because of XYZ are there other safeguards I can put in place to prevent such misguided change?
I don't know your exact design but as I understand from the comments, you're using property to return a resource that needs to be discarded properly with using. If somebody else sets the property the handle to the IDispoable is lost, so it's up to the GC's mercy to dispose it.
Don't use properties to return IDisposable's (or any other resource type hat needs to be explicitly disposed). Use a method instead. That way, the object reference wouldn't be cached in the class, but in the caller. So, caller would be responsible of disposing it. This prevents adding any other code to change the instance in your class, because caching isn't done there anymore.
You can only direct developers to the right direction with a design that describes its intent clearly.
I'd like to validate my assumption.
So I have a class called say ViewModelProvider.
ViewModelProvider is a singleton and has a
IDictionary<string, WeakReference<ViewModelType>>
ViewModelType implements INotifyPropertyChanged.
Basically the ViewModelProvider simply creates ViewModelType instances, and hands them out, if there already exists one it will hand the same instance.
Consumers of these ViewModelType instances just displays them by binding it like so:
<ContentPresenter Content="{Binding VMInstance}" />
The views are instantiated using typed DataTemplates.
With all that out of the way.
When a ViewModel is databound it's instance is referenced implicitly by the WPF framework subscribing to the PropertyChanged handler from INotifyPropertyChanged.
During this time if my understanding is correct the ViewModelType's instance is held by both the WeakReference and also by the WPF Binding. Is this correct?
When the view is unloaded or destroyed, resulting the PropertyChanged event handler from being unsubscribed, ViewModelType's instance is now ONLY held by WeakReference, meaning it can be collected at any point in time now by the GC, is this correct as well?
Everytime someone asks for a specific key'd ViewModelType, I will have to check if the WeakReference's referenced instance is collected or not, before re-initialising and handing it back, is this correct?
Also does anyone see any issues with this way of having a view model cache mechanism in place.
Thanks.
In the process of adhering to code analysis errors, I'm changing my properties to have private setters. Then I started trying to understand why a bit more. From some research, MS says this:
A writable collection property allows a user to replace the collection with a completely different collection.
And the answer, here, states:
Adding a public setter on a List<T> object is dangerous.
But the reason why it's dangerous is not listed. And that's the part where I'm curious.
If we have this collection:
public List<Foo> Foos { get; set; }
Why make the setter private? Apparently we don't want client code to replace the collection, but if a client can remove every element, and then add whatever they want, what's the point? Is that not the same as replacing the collection entirely? How is value provided by following this code analysis rule?
Not exposing the setter prevents a situation where the collection is assigned a value of null. There's a difference between null and a collection without any values. Consider:
for (var value in this.myCollection){ // do something
When there are no values (i.e. someone has called Remove on every value), nothing bad happens. When this.myCollection is null, however, a NullReferenceException will be thrown.
Code Analysis is making the assumption that your code doesn't check that myCollection is null before operating on it.
It's probably also an additional safeguard for the thread-safe collection types defined in System.Collections.Concurrent. Imagine some thread trying to replace the entire collection by overwritting it. By getting rid of the public setter, the only option the thread has is to call the thread-safe Add and Remove methods.
If you're exposing an IList (which would be better practice) the consumer could replace the collection with an entirely different class that implements IList, which could have unpredictable effects. You could have subscribed to events on that collection, or on items in that collection that you're now incorrectly responding to.
In addition to SimpleCoder's null checking (which is, of course, important), there's other things you need to consider.
Someone could replace the List, causing big problems in thread safety
Events to a replaced List won't be sent to subscribers of the old one
You're exposing much, much more behavior then you need to. For example, I wouldn't even make the getter public.
To clarify point 3, don't do cust.Orders.clear(), but make a function called clearOrders() instead.
What if a customer isn't allowed to go over a credit limit? You have no control over that if you expose the list. You'd have to check that (and every other piece of business logic) every place where you might add an order. Yikes! That's a lot of potential for bugs. Instead, you can place it all in an addOrder(Order o) function and be right as rain.
For almost every (I'd say every, but sometimes cheating feels good...) business class, every property should be private for get and set, and if feasible make them readonly too. In this way, users of your class get only behaviors. Protect as much of your data as you can!
ReadOnlyCollection and ReadOnlyObservableCollection exists only for read only collection scenearios.
ReadOnlyObservableCollection is very useful for one way binding in WPF/Silverlight/Metro apps.
If you have a Customer class with a List Property then this property should always have a private setter else it can be changed from outside the customer object via:
customer.Orders = new List<Order>
//this could overwrite data.
Always use the add and remove methods of the collection.
The Orders List should be created inside the Customer constructor via:
Orders = new List<Order>();
Do you really want to check everywhere in your code wether the customer.Orders != null then operate on the Orders?
Or you create the Orders property in your customer object as suggested and never check for customer.Orders == null instead just enumerate the Orders, if its count is zero nothing happens...
I want to create the dictionary of all the ViewModels.
public static Dictionary<string, WeakReference> vmCollection = new Dictionary<string, WeakReference>();
Adding it like this
vmCollection.Add(name, new WeakReference(viewModel));
And calling the required method like this..
((vmCollection[viewModel].Target) as BaseViewModel).NewMessage(message);
Do I need maintain it as a WeakReference? What could be the consequences if I don't maintain it as a WeakReference.
The only consequence of not using a WeakReference is that the reference in your dictionary will prevent the View Model instances from being garbage collected. A WeakReference allows garbage collection (assuming there are no other solid references elsewhere).
An item becomes eligible for garbage collection when it has no references to it. WeakReference does not create a "countable" reference, thus you can keep a sort-of-reference to it, but still let it be eligible if your WeakReference is the only thing left looking at it.
Whether you need it or not really depends on what sort of life-cycle your View Models have. If they need disposing or otherwise "letting go of", then you may need to use WeakReference or expose a way to remove the reference from the dictionary instead.
As I mention in the comments. I tend to err away from using WeakReference as opposed to handling the life-cycle of the relevant objects explicitly. That said, they are useful when you simply don't have visibility of the life-cycle at the relevant points. I think in your situation, you should have the necessary visibility, as these are all likely in the UI layer, and thus should try to not use them.
Here is a resource on the topic:
Weak References MSDN article
Guidelines extract from the above MSDN link:
Use long weak references only when necessary as the state of the
object is unpredictable after finalization.
Avoid using weak references to small objects because the pointer
itself may be as large or larger.
Avoid using weak references as an automatic solution to memory
management problems. Instead, develop an effective caching policy for
handling your application's objects.
I believe the last guideline point applies to your situation.
I took a slightly different approach.
For this example, I only have a single instance, but I'm sure it's fairly easily extendable for multiple instances...
So, on my class I create the following Action (it could be a Func if you need something returned). For my example, I'm just pushing an Exception around:
private static Action<Exception> StaticAccessorToInstanceMethod { get; set; }
And the instance method I want to call is:
public void HandleExceptionDetails(Exception e)
{
// Content of the method on the instance
}
I then have this in my constructor:
StaticAccessorToInstanceMethod = this.HandleExceptionDetails;
And the following in the destructor:
StaticAccessorToInstanceMethod = null;
(If you're dealing with multiple instances, then the constructor and destructor code would be a bit different).
Then the static method simply calls the instance method:
public static void HandleGeneralException(Exception ex)
{
StaticAccessorToInstanceMethod(result);
}
I've left out defensive logic.
I have a library which returns a hierarchical list composed of IDictionary, IList and primitive types (string, and ints). At present I cannot change how this data is returned.
I have another strongly typed class which is consuming this data and converting it into business objects. There is a list of "properties" in the data returned, which I want to import into my strongly typed class. I then can dispose of the hierarchy.
My question is this: If I do this:
MyCustomClass.Properties = HierarchicalData["some_name"]
Where MyCustomClass is my strongly typed class, and HierarchicalData is the IDictionary data what happens when I later call:
HierarchicalData = null
Can Hierarchical data be disposed and released? "some_data" in this case is another Dictionary and so technically that is all that needs to be kept. Do I need to do a explicit copy instead of importing, such as:
MyCustomClass.Properties = HierarchicalData["some_name"].ToDictionary<string, string>( /* selector */)
Clarification: I am not worried about the dictionary containing the properties being garbage collected. I want to make sure that HierarchicalData __can__ be deleted as it is quite large and I need to work with several of them.
Yes. Once there are no references to HierarchicalData, it will be a candidate for collection.
Since you have a reference to the data stored for the "some_name" key, that specific element (the other dictionary) will not be collected. However, the other, unreferenced, portions will become unrooted as far as the GC is concerned, and get finalized at some point.
This will work as you expect. Because you will have created a reference to the dictionary referenced by HierarchicalData["some_name"] in another place, the garbage collector will keep it around for you.
You definitely do not need to copy the dictionary.
Assuming that the class returns a standard Dictionary<TKey, TValue>, you probably don't need to do anything else.
The objects probably don't hold references to the dictionary that contains them, so they probably won't prevent the dictionary from being collected.
However, there's no way to be sure without checking; you should inspect the objects in the Visual Studio debugger's Watch window (or look at the source) and see whether they reference the dictionary.
You do not need to perform a copy.
The line:
MyCustomClass.Properties = HierarchicalData["some_name"]
assigns a reference, and while a reference to the object is alive, it will not be garbage collected.
Can Hierarchical data be disposed and released?
You mean by the GC? Not in this case, as it's referenced by your object(s). GC is not going to mess it up.