Project Description
Send property change notifications without specifying property name as a string.

Instead, write properties like this:

    public int Foo
    {
        get { return _foo; }
        set { SetValue(ref _foo, value); }  // <-- no property name here
    }
Note that there is no need to include the name of the property as a string. ActiveSharp reliably and correctly figures that out for itself. It works based on the fact that your property implementation passes the backing field (_foo) by ref. (ActiveSharp uses that "by ref" call to identify which backing field was passed, and from the field it identifies the property).

This approach is much faster and more reliable than inspecting call stacks, which is a commonly-quoted, but fatally flawed, alternative.

Requires .NET 2.0 or later.

Update, Sept 2011: You won't need ActiveSharp in C# 5.  To convert existing ActiveSharp code to C# 5, 
simply edit your SetValue method (described below) to use the new CallerMemberName attribute, instead of using 
ActiveSharp.  No other code changes will be required.


Implementing INotifyPropertyChanged

Option 1: The easiest way is to use ActiveSharp's PropertyChangeHelper:

Add this code to your class or (preferrably) to a base class:

    readonly 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);
    }

Also, add INotifyPropertyChanged to your base class' list of ancestors. Now, you have a base class that provides all the support for derived classes to sent property changed notifications really easily.

In your derived classes, simply implement your properties like this:

    public int Foo
    {
        get { return _foo; }
        set { SetValue(ref _foo, value); }   // assigns value and does prop change notification, all in one line
    }

Note: a reader kindly wrote in with this translation of the code to VB.NET.

Option 2:

If you want more control, you can write your own SetValue method, instead of delegating to the helper class. Someting like this:

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

As you can see, all the "magic" is in ActiveSharp.PropertyMapping.PropertyMap.GetProperty. Given an object, and a field in that object, passed "by ref", the routine finds the property that sets the field. It returns a standard .NET PropertyInfo object. Just read its Name property if all you want is the property name.

More Details

ActiveSharp works using a unique combination of runtime identification of fields that are passed "by ref", and runtime MSIL inspection (to see which properties use those fields). The MSIL inspection is done only once, then cached. The by-ref field lookup is done on every call, but it's very quick (basically just an integer subtraction and a hash table lookup). For full details, see How it works.

Dicsussion thread here for discussion of other things you can do with ActiveSharp, and how it compares with the alternatives.

Blog posts here and here (including the comments)

++++++ NB: A Note Regarding Alternatives +++++

If you don't want this much "funky stuff" inside your application, there are some alternatives:
  1. Always pass string.Empty as the property name in the PropertyChangedEventArgs. This means "consider all my properties to be changed" (see http://msdn.microsoft.com/en-us/library/system.componentmodel.inotifypropertychanged.propertychanged.aspx ). If you do this, then your property setter code never needs to figure out which property it is "running in", since it just passes string.Empty for all of them. In some (many?) cases, this may be an acceptable solution. It is easy to code, easy to refactor, and requires neither ActiveSharp nor any other "special" solution.
  2. Use ActiveSharp as a unit-test tool, rather than an actual part of your application. In this case, you do put hard-coded property names in the setter methods, but ActiveSharp checks those hard-coded strings at unit test time. So, if you rename the property using a refactoring tool, but forget to change the hard-coded string, you'll get a test failure that reminds you to change the string. See Using ActiveSharp as a Unit Test Tool.
  3. Use an AOP tool. These have the arguable disadvantage of more runtime and/or build-time "baggage" than ActiveSharp (i.e. more "funky stuff" rather than less), but they can certainly do the job. This is my favourite post on AOP as a solution for INotifyPropertyChanged.

Performance
For basic performance tests, and their results, see this unit test. The test results show that ActiveSharp is easily fast enough for most usages (and many, many times faster than crawling the call stack - which doesn't work properly anyway).

Finally, on the topic of performance, as of 27 March 2011, there is an alternative API for ActiveSharp (See Optimize performance). It is approximately 4 times faster than the old one. However, because it is harder to use, and the old one is fast enough for all known usages of ActiveSharp, the new API is not yet included in any release. Besides, option 2 above (Using ActiveSharp as a Unit Test Tool) gives the fastest runtime performance of all.

Last edited Sep 22, 2011 at 10:18 AM by johnrusk, version 38