How does INotifyPropertyChanging interface helps limit memory consumption - c#

I am starting to learn LINQ-to-SQL for Windows Phone 8, and came across this article on MSDN.
They show a base class for DataContext which implements both INotifyPropertyChanging and INotifyPropertyChanged. The reasoning for the INotifyPropertyChanging is:
◦The INotifyPropertyChanged interface is used for change tracking.
◦The INotifyPropertyChanging interface helps limit memory consumption
related to change tracking.
The article fails to give any specific references to justify the claim of memory consumption to the INotifyPropertyChanging interface. The article on INotifyPropertyChanging itself just says:
Notifies clients that a property value is changing.
Can someone please explain to me how this interface which limits the memory footprint of an application, just by notifying that a property value is about to change (and not even restricting that change to from happening)?

I can only extrapolate, but I think that's what the author had in mind:
In a world without INotifyPropertyChanging, if the consumer needs the old value of a property, it has to preemptively cache it (because, once the PropertyChanged event is raised, it's too late and the value is already changed). Alternatively, the producer can keep a copy of the old value in distinct properties. Either way, the data remains duplicated all the time.
With INotifyPropertyChanging, the consumer doesn't need to cache anything beforehand. When the PropertyChanging event is raised, it can grab the old value, knowing it's about to change. Then the NotifyPropertyChanged event is raised, the consumer can grab the new value, do whatever with both, then drop them. The data is still duplicated, but only at a certain point of time and for a limited duration.

Okay, I finally found another MSDN article which actually explains how INotifyPropertyChanging will limit memory footprint. Quoting the article (emphasis mine):
Notifications are provided through the PropertyChanging event in property setters. When LINQ to SQL is notified of the first change to an object, it creates a copy of the object and considers the object a candidate for generating an Update statement.
For objects that do not implement INotifyPropertyChanging, LINQ to SQL
maintains a copy of the values that objects had when they were first materialized.
So if you don't implement INotifyPropertyChanging and never update any objects fetched using Linq-SQL, it will still create a copy of the object for every object it creates. By implementing the interface, you can avoid that additional memory usage, and have it create copies only when you actually are making a change to the object state.

Related

CollectionChanged and IList of Items - why the difficulties

I am looking into the topic why a ObservableCollection/ListCollectionView/CollectionView raises a NotSuportedException when calling the CollectionChanged with the parameter of IList.
//Throws an exception
private void collectionChanged_Removed(IList items)
{
if (CollectionChanged != null)
CollectionChanged(this, new NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Remove, items));
}
I have found several Webpages, talking about this topic and they suggest either using the Reset ability to force a complete redraw of the UI, or just simply call for each item the CollectionChanged or some more creative way: http://geekswithblogs.net/NewThingsILearned/archive/2008/01/16/listcollectionviewcollectionview-doesnt-support-notifycollectionchanged-with-multiple-items.aspx
I just cant find the WHY?
For me it makes no sense why this would be the case.
Is there any chance that this lacking feature, which we all face at some point in our Development Cycle, since the Add method just has to much of an overhead when you want to Add multiple items fast, will be implemented any time (.Net 5, C# 6...).
Edit:
In my specific case, I have written my own class :
public class ObservableList<T> : IList<T>, IList, IEnumerable<T>,
INotifyCollectionChanged
{
public event NotifyCollectionChangedEventHandler CollectionChanged;
//other stuff...
}
And still throws the said NotSupportedException.
Inspired by VirtualBlackFox's answer I took a look under the hood of the CollectionView classes in ILSpy. It appears that the primary reason why the lack of support for Range operations is because internally the CollectionView uses a change log to centrally manage pending changes of all kinds and dispatch messages on a per/item basis.
By its very purpose, the CollectionView could store 1000s of records used simultaneously with multiple UI controls representing its underlying data. So, adding or deleting records must be done on an atomic basis to maintain the integrity of the UI controls that access the view information. You can't synchronize incremental changes with multiple UI subscribers using bulk change events without passing the grouping, sorting, and filtering functionality of the CollectionView onto the UI controls that use it.
The CollectionView also derives from System.Windows.Threading.Dispatcher so the issue may be co-related to how it manages work items on it's thread. The call path includes a protected ProcessCollectionChanged method that specifically processes individual changes on the UI thread. So, updating ranges may interfere with the whole threading model it uses to interact with UI elements that use it.
I totally agree that having consumers of the CollectionView pass in an IList to NotifyCollectionChangedEventArgs is silly. It specifically rejects anything with a length != 1 and hard-codes for args.NewItems[0] internally.
As #nmclean said in the comments the problem isn't in the collection emitting CollectionChanged but on the receiving end.
If you look at the code of ListCollectionView (Using DotPeek for example or on new versions of visual studio you can access the reference source code) you will notice that each time the attached collection change it call a method ValidateCollectionChangedEventArgs that throw when there is more than one element changed
private void ValidateCollectionChangedEventArgs(NotifyCollectionChangedEventArgs e)
{
switch (e.Action)
{
case NotifyCollectionChangedAction.Add:
if (e.NewItems.Count == 1)
break;
else
throw new NotSupportedException(System.Windows.SR.Get("RangeActionsNotSupported"));
...
The rest of the class and it's CollectionView base class are already big beasts (2710 and 2027 lines in the source published on the reference source code) so Microsoft might have wanted to avoid supporting a complex case that the collection that they recommend don't create anyway.
(The method handling collection change is already 141 lines in the reference source code and adding multi element support will make it grow even more or need a careful split and potentially break other things...)
I didn't find any suggestions linked to adding support for range events in Microsoft Connect but you should submit your own if it is important for you.
I guess this is mainly for performance reasons. I was also shocked when I saw that CollectionView also does not accept the -1 value for NewStartingIndex or OldStartingIndex. So basically, CollectionView always wants a mapping from items to their indices. However, it does not require this mapping to be exact (which is strange from my point of view), it is allowed that NewStartingIndex is smaller than the correct index (unless it is -1).
I think the root of the problem is that large parts within Microsoft still think that a list is the one and only way to implement a collection, which of course just is not true. Here, the creators of NotifyCollectionChangedEventArgs thought about alternatives (such as linked lists or hashing collections), but the UI guys did not. Or at least they did not want to support these collections as they appear rather rarely.
The temporary solution is useless. It only hides the problems.
The solution could lie in making events where you provide an entire new list to the observers. That way Microsoft won't have to implement efficient range handlers for each type of observer.

Collection properties should be read only - Loophole?

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...

Should our own code subscribe to PropertyChanged?

We have a number of data objects that realize INotifyPropertyChanged to allow for WPF Binding updates. There are also a number of places where our code subscribes to PropertyChanged because we're interested in some value updates.
This results in pretty ugly code where we need to check which property actually changed (we do this using Expressions so it's always type/refactor safe).
Is the preference to raise a specific event (PriceChanged etc...) for when we want to subscribe to it, or hook into PropertyChanged and check the property name?
If a number of properties you want to subscribe to is not very big, I'd create dedicated events as they are better in terms of readability and discoverability.
However, if there are quite a few properties the answer is not so obvious. I usually try to avoid such situations by applying Observer Synchronization pattern (subscribing to Model changes rather than ViewModel). It helps me keep VMs thin.

MVVM - Should I expose ReadOnlyObservableCollection, ReadOnlyCollection, ICollection, etc?

Basically, I was always in the understanding that you should return the expose base types whenever you can and worry about implementation details internally, which makes sense...
But, I'm not sure what to do here. Basically, right now I have:
ReadOnlyObservableCollection<Foo> MyFoos {get; private set; }
I'm wondering if that should be returned as a ReadOnlyCollection<Foo> or an ICollection<Foo> because internally I never really use any observable parts or attempt to write to the collection. WPF seems to not care what I return, it still binds it and triggers the collection changed notification event properly. But, I read somewhere that I should design this to really have any consuming view handle my ViewModel.
So I'm a bit torn here. I'm thinking that leaving it as a ReadOnlyObservableCollection<T> makes the most sense to explicitly tell the consuming view what they can and can not do with the property, but I'm also under the impression that you should reduce down types to their base types when you can. So I'm not sure what to do here. Especially with the fact that WPF doesn't care what type I return, it figures out that it's observable.
I would probably leave it as ReadOnlyObservableCollection because that very specifically states what a consumer of your ViewModel is allowed to do with your collection. Also note that WPF doesn't actually bind directly to your collection, it binds to the return value of CollectionViewSource.GetDefaultView, which returns an ICollectionView. ICollectionView has INotifyCollectionChanged in its contract.
From a performance perspective, you would want to at least use an items source as a collection that implements INotifyCollectionChanged. MVVM provides a lot of benefits but is primarly concerned with unit testing and separation of concerns, so that choice of whether to use a ReadOnlyObservableCollection or an interface like ICollection{T} would be based on your unit testing goals.

Appropriate implementation of IDisposable with Silverlight?

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.

Categories

Resources