| Severity | Error |
| Reported by | PostSharp.Patterns.Common |
| Message | Field/property <DeclaringType>.<Member> must be annotated with a custom attribute [Child], [Reference] or [Parent]. |
Cause
The AggregatableAttribute aspect must know, for each field and automatic property of the class, whether the object it holds is a child of the instance, a reference to another object, or the parent of the instance. PostSharp cannot guess it from the type: an object of a class can be owned by the instance as well as shared with other objects.
PostSharp therefore reports COM002 for each field or automatic property whose type can be a child, typically a class, an interface or a collection, when the member has no ChildAttribute, ReferenceAttribute or ParentAttribute attribute and no rule of rule-based annotation gives its relationship. Fields and properties of a type that cannot be a child, such as a string or a value type, need no attribute.
In the following example, the Product property of InvoiceLine has no relationship attribute.
using System;
using PostSharp;
using PostSharp.Patterns.Model;
namespace Errors.COM002_Error;
[Aggregatable]
public class Product
{
public string Name { get; set; } = "Keyboard";
}
[Aggregatable]
public class InvoiceLine
{
// The property does not say whether the product is a child or a reference.
public Product? Product { get; set; }
public int Quantity { get; set; }
}
public static class Program
{
public static void Main()
{
Product product = new Product();
InvoiceLine line = new InvoiceLine { Product = product, Quantity = 2 };
object? parent = Post.Cast<Product, IAggregatable>( product ).Parent;
Console.WriteLine( $"{line.Quantity} x {line.Product!.Name}, parent of the product: {parent ?? "none"}" );
}
}
error COM002: COM002_Error.cs(17,21): Field/property Errors.COM002_Error.InvoiceLine.Product must be annotated with a custom attribute [Child], [Reference] or [Parent].
Resolution
Add the attribute that describes the relationship:
- ChildAttribute when the instance owns the object, which then gets the instance as its parent.
- ReferenceAttribute when the object belongs to another part of the graph or is shared.
- ParentAttribute when the field or property receives the parent of the instance.
When many fields follow the same convention, you can give their relationship with a rule instead of an attribute on each of them, as described in Rule-Based Annotation.
In the following example, the invoice line refers to the product, which is shared by many lines, so the product has no parent.
using System;
using PostSharp;
using PostSharp.Patterns.Model;
namespace Errors.COM002_Fixed;
[Aggregatable]
public class Product
{
public string Name { get; set; } = "Keyboard";
}
[Aggregatable]
public class InvoiceLine
{
// The product is shared by many invoice lines, so the line only refers to it.
[Reference]
public Product? Product { get; set; }
public int Quantity { get; set; }
}
public static class Program
{
public static void Main()
{
Product product = new Product();
InvoiceLine line = new InvoiceLine { Product = product, Quantity = 2 };
object? parent = Post.Cast<Product, IAggregatable>( product ).Parent;
Console.WriteLine( $"{line.Quantity} x {line.Product!.Name}, parent of the product: {parent ?? "none"}" );
}
}
2 x Keyboard, parent of the product: none
See Also
Reference
AggregatableAttribute
ChildAttribute
ReferenceAttribute
ParentAttribute
Other Resources
Annotating an Object Model for Parent/Child Relationships (Aggregatable)
Rule-Based Annotation