Open sandboxFocusImprove this doc

DOM027: AggregateAllChanges Applied to a Property That Is Not a Collection

Severity Error
Reported by PostSharp.Patterns.Model
Message The [AggregateAllChanges] attribute cannot be applied to the property <Property> because its type does not implement the ICollection or ICollection<T> interface.

Cause

By default, the NotifyPropertyChangedAttribute aspect notifies a property that depends on a collection only when the collection itself is replaced. The AggregateAllChangesAttribute attribute, on the property that holds the collection, makes the aspect also notify the dependent properties when the content of the collection changes.

The attribute supports only collections: PostSharp reports DOM027 when the type of the property implements neither ICollection nor ICollection<T>.

In the following example, the attribute is applied to the ShippingAddress property, whose type is a class with the NotifyPropertyChangedAttribute aspect, not a collection.

using System;
using System.ComponentModel;
using PostSharp.Patterns.Model;

namespace Errors.DOM027_Error;

[NotifyPropertyChanged]
public class Address
{
    public string City { get; set; } = "Prague";
}

[NotifyPropertyChanged]
public class Order
{
    // Address is not a collection.
    [AggregateAllChanges]
    public Address ShippingAddress { get; } = new Address();

    public string ShippingCity => this.ShippingAddress.City;
}

public static class Program
{
    public static void Main()
    {
        var order = new Order();
        ((INotifyPropertyChanged) order).PropertyChanged +=
            ( _, e ) => Console.WriteLine( $"PropertyChanged: {e.PropertyName}" );

        order.ShippingAddress.City = "Brno";
        Console.WriteLine( $"ShippingCity: {order.ShippingCity}" );
    }
}
error DOM027: DOM027_Error.cs(18,20): The [AggregateAllChanges] attribute cannot be applied to the property Errors.DOM027_Error.Order.ShippingAddress because its type does not implement the ICollection or ICollection<T> interface.

Resolution

  • When the property holds an object that notifies its changes, remove the attribute. The aspect already tracks the dependencies in the form this.ShippingAddress.City.
  • When the property holds a collection, give the property a type that implements ICollection<T>, such as ObservableCollection<T>, instead of an interface such as IEnumerable<T>.

In the following example, the attribute is removed, and changing the city of the address notifies ShippingCity.

using System;
using System.ComponentModel;
using PostSharp.Patterns.Model;

namespace Errors.DOM027_Fixed;

[NotifyPropertyChanged]
public class Address
{
    public string City { get; set; } = "Prague";
}

[NotifyPropertyChanged]
public class Order
{
    // Without [AggregateAllChanges], the aspect still tracks this.ShippingAddress.City.
    public Address ShippingAddress { get; } = new Address();

    public string ShippingCity => this.ShippingAddress.City;
}

public static class Program
{
    public static void Main()
    {
        var order = new Order();
        ((INotifyPropertyChanged) order).PropertyChanged +=
            ( _, e ) => Console.WriteLine( $"PropertyChanged: {e.PropertyName}" );

        order.ShippingAddress.City = "Brno";
        Console.WriteLine( $"ShippingCity: {order.ShippingCity}" );
    }
}
PropertyChanged: ShippingCity
ShippingCity: Brno

See Also

Reference

AggregateAllChangesAttribute
NotifyPropertyChangedAttribute

Other Resources

Handling Corner Cases of the NotifyPropertyChanged Aspect