Friday, February 08, 2008

Better Property Change Notification

aka Automatic INotifyPropertyChanged

Some time ago I developed a new way to do property change notification. It consists of code which can automatically figure out which property has changed, without you having to tell it.

Details are here.

I've now put together an updated version, and posted it on CodePlex here.

Here's how to use the new version:

Option 1:

Here's the easiest option...

Add this code to your class or base class:

PropertyChangeHelper _propertyChangeHelper = new PropertyChangeHelper();

public event PropertyChangedEventHandler PropertyChanged
{
add { _propertyChangeHelper.Add(value); }
remove { _propertyChangeHelper.Remove(value); }
}

protected void SetValue<T>(ref T field, T value)
{
_propertyChangeHelper.SetValue
(this, ref field, value);
}
Then write your property setter methods like this:

public int Foo
{
get { return _foo; }
set { SetValue(ref _foo, value); }
}

Option 2:

If you want more control, you can find which property changed like this (and then do whatever you like):

protected void SetValue<T>(ref T field, T value)
{
...
field = value; //Actually assign the new value
PropertyInfo changedProperty = PropertyMap.GetProperty(this, ref field);
// do whatever you like, now that you know which prop was changed
...
}
Key differences in the new version are:

  • No "trial sets". The old version used to call all your property setters, to figure out which fields they corresponded to. That could be annoying, because you ended up recieving calls to the set methods when your objects were not necessarily ready for them. The new version doesn't need to do this. Instead, it inspects the MSIL of the set methods, to figure out what it needs to know. (The inspection is a one-off runtime operation, so it won't be a performance problem.)

  • Fewer contraints on how classes are coded. The old version required that you nominated a special field as the "reference field", to which all others were compared. The new version does not require that. Also, the new version lets you use your own base class (with your own SetValue method, named whatever you want). Fianlly, you can put your own code in the property setter methods (along with the call to your "SetValue" method), something which could cause problems in the old version

  • Helper class for easy implemetation of property change notifications (as above)

  • Granualar implementation, so that you can call some of the implmentaiton classes, but still write the outer "layer" of the API yourself if you need to

  • Lock-free. The new version is threadsafe without explict locks (and without and [ThreadStatic]s). Update 10 Feb: This used to rely on a little trick with generics and static fields; but that doesn't play well with inheriance. It now uses a class I wrote called LazyDictionary, which is basically a dictionary with double-checked locking to ensure that locks are only requested during initialization, and not during the on-going running of the application. (Didn't want a lock request on every property set call!)

  • No separate C++ assembly. The old version used managed C++ to do stuff that C# cannot. The new version uses reflection emit, to produce the corresponding routine on the fly, so that the separate assembly is not required.



Finally, I have resurrected the name "ActiveSharp" (which I used for a previous, abandonned project) for this new version of the code. I did that for two reasons, firstly the new version borrows code from the old ActiveSharp (particulaly the MSIL inspection); and secondly I liked the old name and couldn't think of a better one ;-) Just like the previous "ActiveSharp", this new version is a product of my microISV, Tasman Logic Ltd. (The microISV is not exactly a money-making venture, given that its only product is open-source ;-)

0 Comments:

Post a Comment

Links to this post:

Create a Link

<< Home