| Severity | Error |
| Reported by | PostSharp.Patterns.Model |
| Message | NotifyPropertyChangedAttribute: automatic analysis of property <Property> failed. Method <Method> contains a call to method <CalledMethod>. Calls to static methods and to methods of other objects cannot be analyzed unless they have no return value and no ref or out parameter. To solve this error, remove the call to this method, or mark the method <CalledMethod> with the [Pure] attribute to specify that its result depends only on its arguments. To ignore the dependency to the method <CalledMethod>, add the [SafeForDependencyAnalysis] attribute to the property <Property>. |
Cause
The NotifyPropertyChangedAttribute aspect analyzes the getter of each property at build time to find the fields and properties that its value depends on. It follows the calls to the methods of the current instance, but it does not analyze the other methods that the getter calls. PostSharp reports DOM002 when the getter calls such a method and uses its result, because the result could depend on state that the aspect does not track:
- a static method, also of the same class;
- a method of another object, for example
this.calculator.ComputeTax().
The aspect accepts, in particular, the calls to methods that return nothing and have no ref or out parameter, to methods marked with IgnoreAutoChangeNotificationAttribute, to methods marked with PureAttribute when all the arguments are of immutable types, to operators, to ToString and GetHashCode of object, and to the static methods of the .NET libraries when all the arguments are of immutable types. A call to a virtual method reports DOM011.
<Method> is the method that contains the call: the getter itself, or a method of the same class that the getter calls. PostSharp reports the message on the property.
In the following example, the Total property of Invoice calls the static method TaxCalculator.AddTax.
using System;
using System.ComponentModel;
using PostSharp.Patterns.Model;
namespace Errors.DOM002_Error;
public static class TaxCalculator
{
public static decimal AddTax( decimal amount ) => amount * 1.2m;
}
[NotifyPropertyChanged]
public class Invoice
{
public decimal Subtotal { get; set; }
// The getter calls a method of another class, which the aspect does not analyze.
public decimal Total => TaxCalculator.AddTax( this.Subtotal );
}
public static class Program
{
public static void Main()
{
Invoice invoice = new();
((INotifyPropertyChanged) invoice).PropertyChanged += ( _, e ) => Console.WriteLine( $"PropertyChanged: {e.PropertyName}" );
invoice.Subtotal = 100;
Console.WriteLine( $"Total: {invoice.Total}" );
}
}
error DOM002: DOM002_Error.cs(18,20): NotifyPropertyChangedAttribute: automatic analysis of property Errors.DOM002_Error.Invoice.Total failed. Method Errors.DOM002_Error.Invoice.get_Total contains a call to method Errors.DOM002_Error.TaxCalculator.AddTax(System.Decimal). Calls to static methods and to methods of other objects cannot be analyzed unless they have no return value and no ref or out parameter. To solve this error, remove the call to this method, or mark the method Errors.DOM002_Error.TaxCalculator.AddTax(System.Decimal) with the [Pure] attribute to specify that its result depends only on its arguments. To ignore the dependency to the method Errors.DOM002_Error.TaxCalculator.AddTax(System.Decimal), add the [SafeForDependencyAnalysis] attribute to the property Errors.DOM002_Error.Invoice.Total.
Resolution
- When the result of the method depends only on its arguments, mark the method with the PureAttribute attribute. Its parameters, and the arguments of the call, must then be of immutable types such as
intorstring; PostSharp reports DOM004 for a pure method with another parameter type. The aspect accepts the call without analyzing the method, and still analyzes the arguments, so the property depends on the values that you pass. - Otherwise, move the logic into a method of the same class, which the aspect analyzes, or read the value through a property of an object that implements
INotifyPropertyChanged. - When you know the dependencies of the property better than the aspect does, add the SafeForDependencyAnalysisAttribute attribute to the property, and declare the dependencies that the aspect cannot find with On.
In the following example, TaxCalculator.AddTax is marked as pure, and the aspect notifies Total when Subtotal changes.
using System;
using System.ComponentModel;
using PostSharp.Patterns.Model;
namespace Errors.DOM002_Fixed;
public static class TaxCalculator
{
// The result of a pure method depends only on its arguments, so the aspect accepts the call without analyzing it.
[Pure]
public static decimal AddTax( decimal amount ) => amount * 1.2m;
}
[NotifyPropertyChanged]
public class Invoice
{
public decimal Subtotal { get; set; }
public decimal Total => TaxCalculator.AddTax( this.Subtotal );
}
public static class Program
{
public static void Main()
{
Invoice invoice = new();
((INotifyPropertyChanged) invoice).PropertyChanged += ( _, e ) => Console.WriteLine( $"PropertyChanged: {e.PropertyName}" );
invoice.Subtotal = 100;
Console.WriteLine( $"Total: {invoice.Total}" );
}
}
PropertyChanged: Subtotal
PropertyChanged: Total
Total: 120.0
See Also
Reference
NotifyPropertyChangedAttribute
PureAttribute
SafeForDependencyAnalysisAttribute
On
Other Resources