tags:

views:

198

answers:

6

I have a function that is to be called if a list has changed since it was last called, what would be the best way of implementing this?

ex:

List<A> OurList = new List<A>();
private void Update()
{
    Boolean Changed = //?    
    if(Changed) CheckList(OurList);
}

I would have assumed make a variable to store the old list and compare, but how would I update the old list to the new list without copying it all out? (If I do an assign, it will update the "old list" too)

+11  A: 

The most efficient way would be to wrap the List<> in your own class and have all the mutating methods (Add, Remove) set a boolean flag.

Your Method can then just look at that flag and reset it.

Henk Holterman
There could also be some kind of event - listener system which notifies interested parties when the collection has changed.
Carlos
This sounds like the best way, I guess it would be a lot easier to have a custom collection for a few things that I'm currently using the list for. Thanks :)
Blam
+1  A: 
  • Restrict access to the list.
  • Allow changes only through a prescribed API.
  • In that API, set a flag whenever the ChangeList method is called.
James Curran
+1  A: 

Are you trying to see if the List itself changed (adding/removing items), or if an item on the list changed.

If you're simply looking to see if a list had an item added/removed, the easiest would be to wrap the List in a new class and override the Add/Remove methods for your object to trigger a boolean.

The more complicated requirement is if you need to know if an item contained on the list has changed (a property or field in the class object that is referenced in the list). If that's the case, it depends on your specific situation. You could put in the setter for the properties for those classes a way to trigger a boolean that would do the same thing as before. But this depends on the complexity of the class in the generic list.

NebuSoft
+5  A: 

If you're using .NET 4.0, you could use the ObservableCollection class. (prior to 4.0, you would need to reference WPF).

Once you create your list, just add a handler to the CollectionChanged event.

Robaticus
Referencing WPF isn't ideal and having .NET 3.5 is a requirement, but thanks anyway :)
Blam
@robaticus: Jinx! :>
dthorpe
+16  A: 

Use an ObservableCollection<T> instead of a List, then subscribe to the CollectionChanged event.

This way, you will be told when the list is changed instead of having to scan the data to figure out what happened after the fact.

dthorpe
@dthorpe - we think alike and in a similar timeframe. About a minute and a half different.
Robaticus
+1: Why roll your own when there's a perfectly good implementation available? See also [NotifyCollectionChangedEventArgs](http://msdn.microsoft.com/en-us/library/system.collections.specialized.notifycollectionchangedeventargs_members.aspx).
on .Net 3.5, but thanks anyway :)
Blam
@Jeff: The event could be useful but it is different from the method approach that was asked for. They are not always easily exchangeable.
Henk Holterman
+2  A: 

Your best bet would be to use an ObservableCollection<T> or BindingList<T> to get push notification of a change. You could also subclass Collection<T> if you want any custom behaviour.

To answer your question as asked (except for the cpu-intensive bit), you can use an existing feature of List<T>: it maintains its own version internally so that it can throw if the collection has changed during enumeration.

This is based on analyzing code from reflector. It is not part of any contract, so it is liable to break at any time. It may also not work in a partial-trust environment. Please use with care:

public static int GetVersion<T>(this List<T> list)
{
    return (int)list.GetType()
                    .GetField("_version", BindingFlags.Instance | BindingFlags.NonPublic)
                    .GetValue(list);
}

...

private int _lastCheckedVersion = 0;

private void Update()
{
    int currentVersion = ourList.GetVersion();

    if(currentVersion != _lastCheckedVersion) CheckList(ourList);

    _lastCheckedVersion = currentVersion;
}
Ani