Open sandboxFocusImprove this doc

COM003: Relationship Attribute Applied to a Non-Automatic Property

Severity Error
Reported by PostSharp.Patterns.Common
Message Cannot apply the [<Attribute>] attribute to the "<Property>" property because it is not an automatic property. Apply it instead to the backing field.

Cause

The AggregatableAttribute aspect tracks the parent/child relationships of an object through the fields that store them. On an automatic property, PostSharp finds the field that the compiler generates. On a property with its own get or set accessor, PostSharp cannot tell which field the property reads or writes, if any, so it reports COM003 when the property has a ChildAttribute, ReferenceAttribute or ParentAttribute attribute.

In the following example, the Address property of Customer checks its value in its set accessor, so it is not an automatic property.

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

namespace Errors.COM003_Error;

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

[Aggregatable]
public class Customer
{
    private Address? address;

    // The attribute is on a property that has its own accessors.
    [Child]
    public Address? Address
    {
        get => this.address;
        set => this.address = value ?? throw new ArgumentNullException( nameof(value) );
    }
}

public static class Program
{
    public static void Main()
    {
        Customer customer = new Customer { Address = new Address() };

        object? parent = Post.Cast<Address, IAggregatable>( customer.Address! ).Parent;
        Console.WriteLine( $"City: {customer.Address!.City}, parent of the address: {parent?.GetType().Name ?? "none"}" );
    }
}
error COM003: COM003_Error.cs(20,21): Cannot apply the [ChildAttribute] attribute to the "Errors.COM003_Error.Customer.Address" property because it is not an automatic property. Apply it instead to the backing field.

Resolution

Move the attribute from the property to the field that stores its value. Alternatively, when the property needs no logic in its accessors, make it an automatic property and keep the attribute on it.

In the following example, the attribute is on the address field, and the address gets the customer as its parent.

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

namespace Errors.COM003_Fixed;

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

[Aggregatable]
public class Customer
{
    // The attribute is on the field that stores the value of the property.
    [Child]
    private Address? address;

    public Address? Address
    {
        get => this.address;
        set => this.address = value ?? throw new ArgumentNullException( nameof(value) );
    }
}

public static class Program
{
    public static void Main()
    {
        Customer customer = new Customer { Address = new Address() };

        object? parent = Post.Cast<Address, IAggregatable>( customer.Address! ).Parent;
        Console.WriteLine( $"City: {customer.Address!.City}, parent of the address: {parent?.GetType().Name ?? "none"}" );
    }
}
City: Prague, parent of the address: Customer

See Also

Reference

AggregatableAttribute
ChildAttribute
ReferenceAttribute
ParentAttribute

Other Resources

Annotating an Object Model for Parent/Child Relationships (Aggregatable)