This is the online documentation for PostSharp 5.0.
Download PDF or CHM. Go to v4.3 or v5.0

Handling Corner Cases of the NotifyPropertyChanged Aspect

PostSharp includes a number of attributes for customizing the default behavior and for handling special dependencies.

This topic contains the following sections:

Ignoring changes to properties

Use the IgnoreAutoChangeNotificationAttribute class attribute to prevent an OnPropertyChanged event from being invoked when setting a property.

Example

In this example, the CustomerModel class contains a Country property amongst others. To prevent a property notification from being invoked when the value of this property is set, simply place the IgnoreAutoChangeNotificationAttribute attribute above the property.

C#
[NotifyPropertyChanged]
public class CustomerModel 
{ 
    public string FirstName { get; set; } 
    public string LastName { get; set; } 
    public string Phone { get; set; } 
    public string Mobile { get; set; } 
    public string Email { get; set; } 

    [IgnoreAutoChangeNotification]
    public string Country { get; set;}
}
Handling virtual calls, delegates, external methods, or complex data flows

If a property getter calls a virtual method from its class or a delegate, or references a property of another object (without using canonical form this.field.Property), PostSharp will generate an error because it cannot resolve such a dependency at build time. The same limitations apply when your property getter contains complex data flows, such as loops, or calls to methods (except property getters) of other classes.

When this happens, you can either refactor your code so that it can be automatically analyzed by PostSharp, or you can take over the responsibility for analyzing the code.

Taking responsibility for dependency analysis

To suppress the error that PostSharp emits when it is unable to fully analyze your code, add the SafeForDependencyAnalysisAttribute custom attribute to the property accessor (or in any method used by the property accessor).

Note Note

By using SafeForDependencyAnalysisAttribute, you are taking the responsibility that your code only has dependencies that are given either in the canonical form of this.field.Property either explicitly using the Depends.On() construct (see below). If you are using this custom attribute but have non-canonical dependencies, some property changes may not be detected in which case no notification will be generated.

Adding dependencies manually

Even when a method has the SafeForDependencyAnalysisAttribute attribute, PostSharp still discovers the dependencies that are in canonical form this.field.Property. However, PostSharp does not discover dependencies hidden under delegate or virtual method calls.

To explicitly add a dependency to a property, you can use the Depends.On() method. The expression passed to the Depends.On() must be in canonical form this.field.Property, i.e. Depends.On( this.field.Property ).

Example

In the following example, the CustomerModel class contains a virtual method called ValidateCountry which is used by the get accessor of its Country property. The presence of the call to the virtual method prevents PostSharp from fully understanding the dependencies of the Country property. PostSharp discovers the dependency to the _country field but cannot analyze the implementations of the ValidateCountry method, and therefore emits an error. By adding the SafeForDependencyAnalysisAttribute attribute, to the Country property, you remove the error.

Even if you remove the error, PostSharp still analyzes the Country property getter and finds the dependency on the _country field. However, it does not follow the call to the ValidateCountry method and does not find the dependency to the Continent property. That is why we have to add this dependency manually by calling the Depends.On method.

C#
[NotifyPropertyChanged]
public class Address 
{ 
  string _country;
  public string Continent { get; set; }

  public virtual bool ValidateCountry(string country)
  {
     return GeoService.ContinentContains( this.Continent, country );
  }

  [SafeForDependencyAnalysisAttribute]
  public string Country 
  { 
    get
    {
      Depends.On( this.Continent );

      if(this.ValidateCountry(_country))
        return _country;
      else
        return "Lilliput";
    }

    set;
  }
}
Handling dependencies on pure methods

Often times a property will depend on a method which is solely dependent on its input parameters to produce a return value. These methods are called pure and do not need to be analyzed. To mark a method as pure, use the PureAttribute custom attribute.

Example

Consider the following variation to CustomerModel where the ValidPhoneNumber property logic has been moved into a static method called GetValidPhoneNumber() which exists in a separate helper class called ContactHelper:

Since GetValidPhoneNumber() is a standalone method of another class, it is not analyzed. Therefore the PureAttribute attribute needs to be applied to this method to acknowledge this dependency.

C#
public class ContactHelper
{
  [Pure]
  public static string GetValidPhoneNumber(string firstPhoneNumber, string secondPhoneNumber)
  {
    return firstPhoneNumber ?? secondPhoneNumber;
  }
}

[NotifyPropertyChanged]
public class CustomerModel 
{ 
  public Contact PrimaryContact {get; set;}
  public Contact SecondaryContact {get; set;}

  public string ValidPhoneNumber
  { 
    get {
      return ContactHelper.GetValidPhoneNumber(this.PrimaryContact.Phone, this.SecondaryContact.Phone);
    }
  }
}
See Also